From 9671f6e8d5edb07cb0dd0bd38fc2c3d29960458f Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Mon, 27 Apr 2020 15:22:05 +0200 Subject: [PATCH] [lldb] Remove NativeProcessDarwin this is dead and non-functional code that hasn't been touched (modulo refactors) since it was checked in (as an "NFC, with no review and tests) in 2016. Anyone interested in adding darwin support to lldb-server can look this up in git history. --- lldb/source/Plugins/Process/Darwin/CFBundle.cpp | 68 - lldb/source/Plugins/Process/Darwin/CFBundle.h | 35 - lldb/source/Plugins/Process/Darwin/CFString.cpp | 153 -- lldb/source/Plugins/Process/Darwin/CFString.h | 40 - lldb/source/Plugins/Process/Darwin/CFUtils.h | 75 - .../Process/Darwin/DarwinProcessLauncher.cpp | 638 -------- .../Plugins/Process/Darwin/DarwinProcessLauncher.h | 48 - lldb/source/Plugins/Process/Darwin/LaunchFlavor.h | 32 - .../Plugins/Process/Darwin/MachException.cpp | 514 ------- lldb/source/Plugins/Process/Darwin/MachException.h | 139 -- .../Plugins/Process/Darwin/NativeProcessDarwin.cpp | 1535 -------------------- .../Plugins/Process/Darwin/NativeProcessDarwin.h | 337 ----- .../Plugins/Process/Darwin/NativeThreadDarwin.cpp | 281 ---- .../Plugins/Process/Darwin/NativeThreadDarwin.h | 165 --- .../Process/Darwin/NativeThreadListDarwin.cpp | 701 --------- .../Process/Darwin/NativeThreadListDarwin.h | 138 -- 16 files changed, 4899 deletions(-) delete mode 100644 lldb/source/Plugins/Process/Darwin/CFBundle.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/CFBundle.h delete mode 100644 lldb/source/Plugins/Process/Darwin/CFString.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/CFString.h delete mode 100644 lldb/source/Plugins/Process/Darwin/CFUtils.h delete mode 100644 lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h delete mode 100644 lldb/source/Plugins/Process/Darwin/LaunchFlavor.h delete mode 100644 lldb/source/Plugins/Process/Darwin/MachException.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/MachException.h delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp delete mode 100644 lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp b/lldb/source/Plugins/Process/Darwin/CFBundle.cpp deleted file mode 100644 index bccf73a..0000000 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- CFBundle.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#include "CFBundle.h" -#include "CFString.h" - -// CFBundle constructor -CFBundle::CFBundle(const char *path) - : CFReleaser(), m_bundle_url() { - if (path && path[0]) - SetPath(path); -} - -// CFBundle copy constructor -CFBundle::CFBundle(const CFBundle &rhs) - : CFReleaser(rhs), m_bundle_url(rhs.m_bundle_url) {} - -// CFBundle copy constructor -CFBundle &CFBundle::operator=(const CFBundle &rhs) { - *this = rhs; - return *this; -} - -// Destructor -CFBundle::~CFBundle() {} - -// Set the path for a bundle by supplying a -bool CFBundle::SetPath(const char *path) { - CFAllocatorRef alloc = kCFAllocatorDefault; - // Release our old bundle and ULR - reset(); // This class is a CFReleaser - m_bundle_url.reset(); - // Make a CFStringRef from the supplied path - CFString cf_path; - cf_path.SetFileSystemRepresentation(path); - if (cf_path.get()) { - // Make our Bundle URL - m_bundle_url.reset(::CFURLCreateWithFileSystemPath( - alloc, cf_path.get(), kCFURLPOSIXPathStyle, true)); - if (m_bundle_url.get()) { - reset(::CFBundleCreate(alloc, m_bundle_url.get())); - } - } - return get() != NULL; -} - -CFStringRef CFBundle::GetIdentifier() const { - CFBundleRef bundle = get(); - if (bundle != NULL) - return ::CFBundleGetIdentifier(bundle); - return NULL; -} - -CFURLRef CFBundle::CopyExecutableURL() const { - CFBundleRef bundle = get(); - if (bundle != NULL) - return CFBundleCopyExecutableURL(bundle); - return NULL; -} diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.h b/lldb/source/Plugins/Process/Darwin/CFBundle.h deleted file mode 100644 index f49dc30..0000000 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- CFBundle.h ----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFBundle_h__ -#define __CFBundle_h__ - -#include "CFUtils.h" - -class CFBundle : public CFReleaser { -public: - // Constructors and Destructors - CFBundle(const char *path = NULL); - CFBundle(const CFBundle &rhs); - CFBundle &operator=(const CFBundle &rhs); - virtual ~CFBundle(); - bool SetPath(const char *path); - - CFStringRef GetIdentifier() const; - - CFURLRef CopyExecutableURL() const; - -protected: - CFReleaser m_bundle_url; -}; - -#endif // #ifndef __CFBundle_h__ diff --git a/lldb/source/Plugins/Process/Darwin/CFString.cpp b/lldb/source/Plugins/Process/Darwin/CFString.cpp deleted file mode 100644 index 6d41ea2..0000000 --- a/lldb/source/Plugins/Process/Darwin/CFString.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===-- CFString.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#include "CFString.h" -#include -#include - -// CFString constructor -CFString::CFString(CFStringRef s) : CFReleaser(s) {} - -// CFString copy constructor -CFString::CFString(const CFString &rhs) : CFReleaser(rhs) {} - -// CFString copy constructor -CFString &CFString::operator=(const CFString &rhs) { - if (this != &rhs) - *this = rhs; - return *this; -} - -CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding) - : CFReleaser() { - if (cstr && cstr[0]) { - reset( - ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); - } -} - -// Destructor -CFString::~CFString() {} - -const char *CFString::GetFileSystemRepresentation(std::string &s) { - return CFString::FileSystemRepresentation(get(), s); -} - -CFStringRef CFString::SetFileSystemRepresentation(const char *path) { - CFStringRef new_value = NULL; - if (path && path[0]) - new_value = - ::CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); - reset(new_value); - return get(); -} - -CFStringRef CFString::SetFileSystemRepresentationFromCFType(CFTypeRef cf_type) { - CFStringRef new_value = NULL; - if (cf_type != NULL) { - CFTypeID cf_type_id = ::CFGetTypeID(cf_type); - - if (cf_type_id == ::CFStringGetTypeID()) { - // Retain since we are using the existing object - new_value = (CFStringRef)::CFRetain(cf_type); - } else if (cf_type_id == ::CFURLGetTypeID()) { - new_value = - ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle); - } - } - reset(new_value); - return get(); -} - -CFStringRef -CFString::SetFileSystemRepresentationAndExpandTilde(const char *path) { - std::string expanded_path; - if (CFString::GlobPath(path, expanded_path)) - SetFileSystemRepresentation(expanded_path.c_str()); - else - reset(); - return get(); -} - -const char *CFString::UTF8(std::string &str) { - return CFString::UTF8(get(), str); -} - -// Static function that puts a copy of the UTF8 contents of CF_STR into STR and -// returns the C string pointer that is contained in STR when successful, else -// NULL is returned. This allows the std::string parameter to own the extracted -// string, -// and also allows that string to be returned as a C string pointer that can be -// used. - -const char *CFString::UTF8(CFStringRef cf_str, std::string &str) { - if (cf_str) { - const CFStringEncoding encoding = kCFStringEncodingUTF8; - CFIndex max_utf8_str_len = CFStringGetLength(cf_str); - max_utf8_str_len = - CFStringGetMaximumSizeForEncoding(max_utf8_str_len, encoding); - if (max_utf8_str_len > 0) { - str.resize(max_utf8_str_len); - if (!str.empty()) { - if (CFStringGetCString(cf_str, &str[0], str.size(), encoding)) { - str.resize(strlen(str.c_str())); - return str.c_str(); - } - } - } - } - return NULL; -} - -// Static function that puts a copy of the file system representation of CF_STR -// into STR and returns the C string pointer that is contained in STR when -// successful, else NULL is returned. This allows the std::string parameter to -// own the extracted string, and also allows that string to be returned as a C -// string pointer that can be used. - -const char *CFString::FileSystemRepresentation(CFStringRef cf_str, - std::string &str) { - if (cf_str) { - CFIndex max_length = - ::CFStringGetMaximumSizeOfFileSystemRepresentation(cf_str); - if (max_length > 0) { - str.resize(max_length); - if (!str.empty()) { - if (::CFStringGetFileSystemRepresentation(cf_str, &str[0], - str.size())) { - str.erase(::strlen(str.c_str())); - return str.c_str(); - } - } - } - } - str.erase(); - return NULL; -} - -CFIndex CFString::GetLength() const { - CFStringRef str = get(); - if (str) - return CFStringGetLength(str); - return 0; -} - -const char *CFString::GlobPath(const char *path, std::string &expanded_path) { - glob_t globbuf; - if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) { - expanded_path = globbuf.gl_pathv[0]; - ::globfree(&globbuf); - } else - expanded_path.clear(); - - return expanded_path.c_str(); -} diff --git a/lldb/source/Plugins/Process/Darwin/CFString.h b/lldb/source/Plugins/Process/Darwin/CFString.h deleted file mode 100644 index d1bd568..0000000 --- a/lldb/source/Plugins/Process/Darwin/CFString.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- CFString.h ----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 1/16/08. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFString_h__ -#define __CFString_h__ - -#include "CFUtils.h" -#include - -class CFString : public CFReleaser { -public: - // Constructors and Destructors - CFString(CFStringRef cf_str = NULL); - CFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); - CFString(const CFString &rhs); - CFString &operator=(const CFString &rhs); - virtual ~CFString(); - - const char *GetFileSystemRepresentation(std::string &str); - CFStringRef SetFileSystemRepresentation(const char *path); - CFStringRef SetFileSystemRepresentationFromCFType(CFTypeRef cf_type); - CFStringRef SetFileSystemRepresentationAndExpandTilde(const char *path); - const char *UTF8(std::string &str); - CFIndex GetLength() const; - static const char *UTF8(CFStringRef cf_str, std::string &str); - static const char *FileSystemRepresentation(CFStringRef cf_str, - std::string &str); - static const char *GlobPath(const char *path, std::string &expanded_path); -}; - -#endif // #ifndef __CFString_h__ diff --git a/lldb/source/Plugins/Process/Darwin/CFUtils.h b/lldb/source/Plugins/Process/Darwin/CFUtils.h deleted file mode 100644 index 0ef7b18..0000000 --- a/lldb/source/Plugins/Process/Darwin/CFUtils.h +++ /dev/null @@ -1,75 +0,0 @@ -//===-- CFUtils.h -----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 3/5/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __CFUtils_h__ -#define __CFUtils_h__ - -#include - -#ifdef __cplusplus - -// Templatized CF helper class that can own any CF pointer and will -// call CFRelease() on any valid pointer it owns unless that pointer is -// explicitly released using the release() member function. -template class CFReleaser { -public: - // Type names for the value - typedef T element_type; - - // Constructors and destructors - CFReleaser(T ptr = NULL) : _ptr(ptr) {} - CFReleaser(const CFReleaser ©) : _ptr(copy.get()) { - if (get()) - ::CFRetain(get()); - } - virtual ~CFReleaser() { reset(); } - - // Assignments - CFReleaser &operator=(const CFReleaser ©) { - if (copy != *this) { - // Replace our owned pointer with the new one - reset(copy.get()); - // Retain the current pointer that we own - if (get()) - ::CFRetain(get()); - } - } - // Get the address of the contained type - T *ptr_address() { return &_ptr; } - - // Access the pointer itself - const T get() const { return _ptr; } - T get() { return _ptr; } - - // Set a new value for the pointer and CFRelease our old - // value if we had a valid one. - void reset(T ptr = NULL) { - if (ptr != _ptr) { - if (_ptr != NULL) - ::CFRelease(_ptr); - _ptr = ptr; - } - } - - // Release ownership without calling CFRelease - T release() { - T tmp = _ptr; - _ptr = NULL; - return tmp; - } - -private: - element_type _ptr; -}; - -#endif // #ifdef __cplusplus -#endif // #ifndef __CFUtils_h__ diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp deleted file mode 100644 index f112678..0000000 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ /dev/null @@ -1,638 +0,0 @@ -//===-- DarwinProcessLauncher.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// -// DarwinProcessLauncher.cpp -// lldb -// -// Created by Todd Fiala on 8/30/16. -// -// - -#include "DarwinProcessLauncher.h" - -// C includes -#include -#include -#include -#include - -#ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 -#endif - -// LLDB includes -#include "lldb/lldb-enumerations.h" - -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/StreamString.h" -#include "llvm/Support/Errno.h" - -#include "CFBundle.h" -#include "CFString.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; -using namespace lldb_private::darwin_process_launcher; - -namespace { -static LaunchFlavor g_launch_flavor = LaunchFlavor::Default; -} - -namespace lldb_private { -namespace darwin_process_launcher { - -static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) { - int mib[CTL_MAXNAME] = { - 0, - }; - size_t len = CTL_MAXNAME; - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl(mib, static_cast(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; -} - -static bool ResolveExecutablePath(const char *path, char *resolved_path, - size_t resolved_path_size) { - if (path == NULL || path[0] == '\0') - return false; - - char max_path[PATH_MAX]; - std::string result; - CFString::GlobPath(path, result); - - if (result.empty()) - result = path; - - struct stat path_stat; - if (::stat(path, &path_stat) == 0) { - if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { - CFBundle bundle(path); - CFReleaser url(bundle.CopyExecutableURL()); - if (url.get()) { - if (::CFURLGetFileSystemRepresentation( - url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) - return true; - } - } - } - - if (realpath(path, max_path)) { - // Found the path relatively... - ::strncpy(resolved_path, max_path, resolved_path_size); - return strlen(resolved_path) + 1 < resolved_path_size; - } else { - // Not a relative path, check the PATH environment variable if the - const char *PATH = getenv("PATH"); - if (PATH) { - const char *curr_path_start = PATH; - const char *curr_path_end; - while (curr_path_start && *curr_path_start) { - curr_path_end = strchr(curr_path_start, ':'); - if (curr_path_end == NULL) { - result.assign(curr_path_start); - curr_path_start = NULL; - } else if (curr_path_end > curr_path_start) { - size_t len = curr_path_end - curr_path_start; - result.assign(curr_path_start, len); - curr_path_start += len + 1; - } else - break; - - result += '/'; - result += path; - struct stat s; - if (stat(result.c_str(), &s) == 0) { - ::strncpy(resolved_path, result.c_str(), resolved_path_size); - return result.size() + 1 < resolved_path_size; - } - } - } - } - return false; -} - -// TODO check if we have a general purpose fork and exec. We may be -// able to get rid of this entirely. -static Status ForkChildForPTraceDebugging(const char *path, char const *argv[], - char const *envp[], ::pid_t *pid, - int *pty_fd) { - Status error; - if (!path || !argv || !envp || !pid || !pty_fd) { - error.SetErrorString("invalid arguments"); - return error; - } - - // Use a fork that ties the child process's stdin/out/err to a pseudo - // terminal so we can read it in our MachProcess::STDIOThread as unbuffered - // io. - PseudoTerminal pty; - char fork_error[256]; - memset(fork_error, 0, sizeof(fork_error)); - *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error))); - if (*pid < 0) { - // Status during fork. - *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID); - error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__, - fork_error); - return error; - } else if (pid == 0) { - // Child process - - // Debug this process. - ::ptrace(PT_TRACE_ME, 0, 0, 0); - - // Get BSD signals as mach exceptions. - ::ptrace(PT_SIGEXC, 0, 0, 0); - - // If our parent is setgid, lets make sure we don't inherit those extra - // powers due to nepotism. - if (::setgid(getgid()) == 0) { - // Let the child have its own process group. We need to execute this call - // in both the child and parent to avoid a race condition between the two - // processes. - - // Set the child process group to match its pid. - ::setpgid(0, 0); - - // Sleep a bit to before the exec call. - ::sleep(1); - - // Turn this process into the given executable. - ::execv(path, (char *const *)argv); - } - // Exit with error code. Child process should have taken over in above exec - // call and if the exec fails it will exit the child process below. - ::exit(127); - } else { - // Parent process - // Let the child have its own process group. We need to execute this call - // in both the child and parent to avoid a race condition between the two - // processes. - - // Set the child process group to match its pid - ::setpgid(*pid, *pid); - if (pty_fd) { - // Release our master pty file descriptor so the pty class doesn't close - // it and so we can continue to use it in our STDIO thread - *pty_fd = pty.ReleaseMasterFileDescriptor(); - } - } - return error; -} - -static Status -CreatePosixSpawnFileAction(const FileAction &action, - posix_spawn_file_actions_t *file_actions) { - Status error; - - // Log it. - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) { - StreamString stream; - stream.PutCString("converting file action for posix_spawn(): "); - action.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - // Validate args. - if (!file_actions) { - error.SetErrorString("mandatory file_actions arg is null"); - return error; - } - - // Build the posix file action. - switch (action.GetAction()) { - case FileAction::eFileActionOpen: { - const int error_code = ::posix_spawn_file_actions_addopen( - file_actions, action.GetFD(), action.GetPath(), - action.GetActionArgument(), 0); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionClose: { - const int error_code = - ::posix_spawn_file_actions_addclose(file_actions, action.GetFD()); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionDuplicate: { - const int error_code = ::posix_spawn_file_actions_adddup2( - file_actions, action.GetFD(), action.GetActionArgument()); - if (error_code != 0) { - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - break; - } - - case FileAction::eFileActionNone: - default: - LLDB_LOGF(log, "%s(): unsupported file action %u", __FUNCTION__, - action.GetAction()); - break; - } - - return error; -} - -static Status PosixSpawnChildForPTraceDebugging(const char *path, - ProcessLaunchInfo &launch_info, - ::pid_t *pid, - cpu_type_t *actual_cpu_type) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!pid) { - error.SetErrorStringWithFormat("%s(): pid arg cannot be null", - __FUNCTION__); - return error; - } - - posix_spawnattr_t attr; - short flags; - if (log) { - StreamString stream; - stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - int error_code; - if ((error_code = ::posix_spawnattr_init(&attr)) != 0) { - LLDB_LOGF(log, "::posix_spawnattr_init(&attr) failed"); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Ensure we clean up the spawnattr structure however we exit this function. - std::unique_ptr spawnattr_up( - &attr, ::posix_spawnattr_destroy); - - flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | - POSIX_SPAWN_SETSIGMASK; - if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) - flags |= _POSIX_SPAWN_DISABLE_ASLR; - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset(&no_signals); - sigfillset(&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); - ::posix_spawnattr_setsigdefault(&attr, &all_signals); - - if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) { - LLDB_LOG(log, - "::posix_spawnattr_setflags(&attr, " - "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}", - flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" - : "", - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - -#if !defined(__arm__) - - // We don't need to do this for ARM, and we really shouldn't now that we have - // multiple CPU subtypes and no posix_spawnattr call that allows us to set - // which CPU subtype to launch... - cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType(); - if (desired_cpu_type != LLDB_INVALID_CPUTYPE) { - size_t ocount = 0; - error_code = - ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount); - if (error_code != 0) { - LLDB_LOG(log, - "::posix_spawnattr_setbinpref_np(&attr, 1, " - "cpu_type = {0:x8}, count => {1}): {2}", - desired_cpu_type, ocount, llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - if (ocount != 1) { - error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np " - "did not set the expected number " - "of cpu_type entries: expected 1 " - "but was %zu", - ocount); - return error; - } - } -#endif - - posix_spawn_file_actions_t file_actions; - if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) { - LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}", - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Ensure we clean up file actions however we exit this. When the - // file_actions_up below goes out of scope, we'll get our file action - // cleanup. - std::unique_ptr - file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy); - - // We assume the caller has setup the file actions appropriately. We are not - // in the business of figuring out what we really need here. lldb-server will - // have already called FinalizeFileActions() as well to button these up - // properly. - const size_t num_actions = launch_info.GetNumFileActions(); - for (size_t action_index = 0; action_index < num_actions; ++action_index) { - const FileAction *const action = - launch_info.GetFileActionAtIndex(action_index); - if (!action) - continue; - - error = CreatePosixSpawnFileAction(*action, &file_actions); - if (!error.Success()) { - LLDB_LOGF(log, - "%s(): error converting FileAction to posix_spawn " - "file action: %s", - __FUNCTION__, error.AsCString()); - return error; - } - } - - // TODO: Verify if we can set the working directory back immediately - // after the posix_spawnp call without creating a race condition??? - const char *const working_directory = - launch_info.GetWorkingDirectory().GetCString(); - if (working_directory && working_directory[0]) - ::chdir(working_directory); - - auto argv = launch_info.GetArguments().GetArgumentVector(); - auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector(); - error_code = ::posix_spawnp(pid, path, &file_actions, &attr, - (char *const *)argv, (char *const *)envp); - if (error_code != 0) { - LLDB_LOG(log, - "::posix_spawnp(pid => {0}, path = '{1}', file_actions " - "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}", - pid, path, &file_actions, &attr, argv, envp, - llvm::sys::StrError(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } - - // Validate we got a pid. - if (pid == LLDB_INVALID_PROCESS_ID) { - error.SetErrorString("posix_spawn() did not indicate a failure but it " - "failed to return a pid, aborting."); - return error; - } - - if (actual_cpu_type) { - *actual_cpu_type = GetCPUTypeForLocalProcess(*pid); - LLDB_LOGF(log, - "%s(): cpu type for launched process pid=%i: " - "cpu_type=0x%8.8x", - __FUNCTION__, *pid, *actual_cpu_type); - } - - return error; -} - -Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - LaunchFlavor *launch_flavor) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!launch_flavor) { - error.SetErrorString("mandatory launch_flavor field was null"); - return error; - } - - if (log) { - StreamString stream; - stream.Printf("NativeProcessDarwin::%s(): launching with the " - "following launch info:", - __FUNCTION__); - launch_info.Dump(stream, nullptr); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - // Retrieve the binary name given to us. - char given_path[PATH_MAX]; - given_path[0] = '\0'; - launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path)); - - // Determine the manner in which we'll launch. - *launch_flavor = g_launch_flavor; - if (*launch_flavor == LaunchFlavor::Default) { - // Our default launch method is posix spawn - *launch_flavor = LaunchFlavor::PosixSpawn; -#if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(given_path, ".app")) { - *launch_flavor = eLaunchFlavorSpringBoard; - } -#endif - } - - // Attempt to resolve the binary name to an absolute path. - char resolved_path[PATH_MAX]; - resolved_path[0] = '\0'; - - LLDB_LOGF(log, "%s(): attempting to resolve given binary path: \"%s\"", - __FUNCTION__, given_path); - - // If we fail to resolve the path to our executable, then just use what we - // were given and hope for the best - if (!ResolveExecutablePath(given_path, resolved_path, - sizeof(resolved_path))) { - LLDB_LOGF(log, - "%s(): failed to resolve binary path, using " - "what was given verbatim and hoping for the best", - __FUNCTION__); - ::strncpy(resolved_path, given_path, sizeof(resolved_path)); - } else { - LLDB_LOGF(log, "%s(): resolved given binary path to: \"%s\"", __FUNCTION__, - resolved_path); - } - - char launch_err_str[PATH_MAX]; - launch_err_str[0] = '\0'; - - // TODO figure out how to handle QSetProcessEvent - // const char *process_event = ctx.GetProcessEvent(); - - // Ensure the binary is there. - struct stat path_stat; - if (::stat(resolved_path, &path_stat) == -1) { - error.SetErrorToErrno(); - return error; - } - - // Fork a child process for debugging - // state_callback(eStateLaunching); - - const auto argv = launch_info.GetArguments().GetConstArgumentVector(); - const auto envp = - launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - - switch (*launch_flavor) { - case LaunchFlavor::ForkExec: { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid, - pty_master_fd); - if (error.Success()) { - launch_info.SetProcessID(static_cast(pid)); - } else { - // Reset any variables that might have been set during a failed launch - // attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - } break; - -#ifdef WITH_FBS - case LaunchFlavor::FBS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingFBS; - if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, - no_stdio, disable_aslr, event_data, - launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a FBS launch, but didn't succeed lets get out - } - } break; -#endif - -#ifdef WITH_BKS - case LaunchFlavor::BKS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingBKS; - if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, - no_stdio, disable_aslr, event_data, - launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a BKS launch, but didn't succeed lets get out - } - } break; -#endif - -#ifdef WITH_SPRINGBOARD - case LaunchFlavor::SpringBoard: { - // .../whatever.app/whatever ? - // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in - // "com.apple.whatever" here - const char *app_ext = strstr(path, ".app/"); - if (app_ext == NULL) { - // .../whatever.app ? - int len = strlen(path); - if (len > 5) { - if (strcmp(path + len - 4, ".app") == 0) { - app_ext = path + len - 4; - } - } - } - if (app_ext) { - std::string app_bundle_path(path, app_ext + strlen(".app")); - if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, - disable_aslr, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a - // non-zero m_pid. - else - break; // We tried a springboard launch, but didn't succeed lets get out - } - } break; -#endif - - case LaunchFlavor::PosixSpawn: { - ::pid_t pid = LLDB_INVALID_PROCESS_ID; - - // Retrieve paths for stdin/stdout/stderr. - cpu_type_t actual_cpu_type = 0; - error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid, - &actual_cpu_type); - if (error.Success()) { - launch_info.SetProcessID(static_cast(pid)); - if (pty_master_fd) - *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); - } else { - // Reset any variables that might have been set during a failed launch - // attempt. - if (pty_master_fd) - *pty_master_fd = -1; - - // We're done. - return error; - } - break; - } - - default: - // Invalid launch flavor. - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown " - "launch flavor %d", - __FUNCTION__, (int)*launch_flavor); - return error; - } - - if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { - // If we don't have a valid process ID and no one has set the error, then - // return a generic error. - if (error.Success()) - error.SetErrorStringWithFormat("%s(): failed to launch, no reason " - "specified", - __FUNCTION__); - } - - // We're done with the launch side of the operation. - return error; -} -} -} // namespaces diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h deleted file mode 100644 index 0e65b56..0000000 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- DarwinProcessLauncher.h ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef DarwinProcessLauncher_h -#define DarwinProcessLauncher_h - -// C headers -#include -#include - -// C++ headers -#include - -// LLDB headers -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-forward.h" - -#include "LaunchFlavor.h" - -namespace lldb_private { -namespace darwin_process_launcher { -// ============================================================================= -/// Launches a process for debugging. -/// -/// \param[inout] launch_info -/// Specifies details about the process to launch (e.g. path, architecture, -/// etc.). On output, includes the launched ProcessID (pid). -/// -/// \param[out] pty_master_fd -/// Returns the master side of the pseudo-terminal used to communicate -/// with stdin/stdout from the launched process. May be nullptr. -/// -/// \param[out] launch_flavor -/// Contains the launch flavor used when launching the process. -// ============================================================================= -Status -LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - lldb_private::process_darwin::LaunchFlavor *launch_flavor); - -} // darwin_process_launcher -} // lldb_private - -#endif /* DarwinProcessLauncher_h */ diff --git a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h b/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h deleted file mode 100644 index cfd76d1..0000000 --- a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- LaunchFlavor.h ---------------------------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LaunchFlavor_h -#define LaunchFlavor_h - -namespace lldb_private { -namespace process_darwin { - -enum class LaunchFlavor { - Default = 0, - PosixSpawn = 1, - ForkExec = 2, -#ifdef WITH_SPRINGBOARD - SpringBoard = 3, -#endif -#ifdef WITH_BKS - BKS = 4, -#endif -#ifdef WITH_FBS - FBS = 5 -#endif -}; -} -} // namespaces - -#endif /* LaunchFlavor_h */ diff --git a/lldb/source/Plugins/Process/Darwin/MachException.cpp b/lldb/source/Plugins/Process/Darwin/MachException.cpp deleted file mode 100644 index 9c20256..0000000 --- a/lldb/source/Plugins/Process/Darwin/MachException.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===-- MachException.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/18/07. -// -//===----------------------------------------------------------------------===// - -#include "MachException.h" - -// C includes -#include -#include -#include - -// C++ includes -#include - -// LLDB includes -#include "lldb/Target/UnixSignals.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/Stream.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -// Routine mach_exception_raise -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, - mach_port_t task, exception_type_t exception, - mach_exception_data_t code, - mach_msg_type_number_t codeCnt); - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exception_port, exception_type_t exception, - const mach_exception_data_t code, mach_msg_type_number_t codeCnt, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -// Routine mach_exception_raise_state_identity -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exception_port, mach_port_t thread, mach_port_t task, - exception_type_t exception, mach_exception_data_t code, - mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, - mach_msg_header_t *OutHeadP); - -static MachException::Data *g_message = NULL; - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exc_port, exception_type_t exc_type, - const mach_exception_data_t exc_data, mach_msg_type_number_t exc_data_count, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt) { - // TODO change to LIBLLDB_LOG_EXCEPTION - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, exc_type = %d (%s), " - "exc_data = 0x%llx, exc_data_count = %d)", - __FUNCTION__, exc_port, exc_type, MachException::Name(exc_type), - (uint64_t)exc_data, exc_data_count); - } - return KERN_FAILURE; -} - -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exc_port, mach_port_t thread_port, mach_port_t task_port, - exception_type_t exc_type, mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count, int *flavor, - thread_state_t old_state, mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, mach_msg_type_number_t *new_stateCnt) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " - "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] = " - "{ 0x%llx, 0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - return KERN_FAILURE; -} - -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port, - mach_port_t task_port, exception_type_t exc_type, - mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) { - LLDB_LOGF(log, - "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " - "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] " - "= { 0x%llx, 0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - if (task_port == g_message->task_port) { - g_message->task_port = task_port; - g_message->thread_port = thread_port; - g_message->exc_type = exc_type; - g_message->exc_data.resize(exc_data_count); - ::memcpy(&g_message->exc_data[0], exc_data, - g_message->exc_data.size() * sizeof(mach_exception_data_type_t)); - return KERN_SUCCESS; - } - return KERN_FAILURE; -} - -bool MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info, - const UnixSignals &signals, - Stream &stream) const { - if (!stop_info) - return false; - - // Zero out the structure. - memset(stop_info, 0, sizeof(struct ThreadStopInfo)); - - if (exc_type == 0) { - stop_info->reason = eStopReasonInvalid; - return true; - } - - // We always stop with a mach exception. - stop_info->reason = eStopReasonException; - // Save the EXC_XXXX exception type. - stop_info->details.exception.type = exc_type; - - // Fill in a text description - const char *exc_name = MachException::Name(exc_type); - if (exc_name) - stream.Printf("%s", exc_name); - else - stream.Printf("%i", exc_type); - - stop_info->details.exception.data_count = exc_data.size(); - - int soft_signal = SoftSignal(); - if (soft_signal) { - const char *sig_str = signals.GetSignalAsCString(soft_signal); - stream.Printf(" EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, - sig_str ? sig_str : "unknown signal"); - } else { - // No special disassembly for exception data, just print it. - size_t idx; - stream.Printf(" data[%llu] = {", - (uint64_t)stop_info->details.exception.data_count); - - for (idx = 0; idx < stop_info->details.exception.data_count; ++idx) { - stream.Printf( - "0x%llx%c", (uint64_t)exc_data[idx], - ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); - } - } - - // Copy the exception data - for (size_t i = 0; i < stop_info->details.exception.data_count; i++) - stop_info->details.exception.data[i] = exc_data[i]; - - return true; -} - -Status MachException::Message::Receive(mach_port_t port, - mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - mach_msg_timeout_t mach_msg_timeout = - options & MACH_RCV_TIMEOUT ? timeout : 0; - if (log && ((options & MACH_RCV_TIMEOUT) == 0)) { - // Dump this log message if we have no timeout in case it never returns - LLDB_LOGF(log, - "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " - "local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = 0, rcv_size = %llu, " - "rcv_name = %#x, timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, - (uint64_t)sizeof(exc_msg.data), port, mach_msg_timeout, - notify_port); - } - - mach_msg_return_t mach_err = - ::mach_msg(&exc_msg.hdr, - options, // options - 0, // Send size - sizeof(exc_msg.data), // Receive size - port, // exception port to watch for - // exception on - mach_msg_timeout, // timeout in msec (obeyed only - // if MACH_RCV_TIMEOUT is ORed - // into the options parameter) - notify_port); - error.SetError(mach_err, eErrorTypeMachKernel); - - // Dump any errors we get - if (error.Fail() && log) { - LLDB_LOGF(log, - "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " - "local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %lu, rcv_name " - "= %#x, timeout = %u, notify = %#x) failed: %s", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 0, - sizeof(exc_msg.data), port, mach_msg_timeout, notify_port, - error.AsCString()); - } - return error; -} - -void MachException::Message::Dump(Stream &stream) const { - stream.Printf(" exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " - "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " - "0x%8.8x }\n", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id); - - stream.Printf(" reply_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " - "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " - "0x%8.8x }", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id); -} - -bool MachException::Message::CatchExceptionRaise(task_t task) { - bool success = false; - state.task_port = task; - g_message = &state; - // The exc_server function is the MIG generated server handling function to - // handle messages from the kernel relating to the occurrence of an exception - // in a thread. Such messages are delivered to the exception port set via - // thread_set_exception_ports or task_set_exception_ports. When an exception - // occurs in a thread, the thread sends an exception message to its exception - // port, blocking in the kernel waiting for the receipt of a reply. The - // exc_server function performs all necessary argument handling for this - // kernel message and calls catch_exception_raise, - // catch_exception_raise_state or catch_exception_raise_state_identity, which - // should handle the exception. If the called routine returns KERN_SUCCESS, a - // reply message will be sent, allowing the thread to continue from the point - // of the exception; otherwise, no reply message is sent and the called - // routine must have dealt with the exception thread directly. - if (mach_exc_server(&exc_msg.hdr, &reply_msg.hdr)) { - success = true; - } else { - Log *log( - GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - LLDB_LOGF(log, - "MachException::Message::%s(): mach_exc_server " - "returned zero...", - __FUNCTION__); - } - g_message = NULL; - return success; -} - -Status MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, - int signal) { - // Reply to the exception... - Status error; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - // If we had a soft signal, we need to update the thread first so it can - // continue without signaling - int soft_signal = state.SoftSignal(); - if (soft_signal) { - int state_pid = -1; - if (inferior_task == state.task_port) { - // This is our task, so we can update the signal to send to it - state_pid = inferior_pid; - soft_signal = signal; - } else { - auto mach_err = ::pid_for_task(state.task_port, &state_pid); - if (mach_err) { - error.SetError(mach_err, eErrorTypeMachKernel); - LLDB_LOGF(log, - "MachException::Message::%s(): pid_for_task() " - "failed: %s", - __FUNCTION__, error.AsCString()); - return error; - } - } - - lldbassert(state_pid != -1); - if (state_pid != -1) { - errno = 0; - caddr_t thread_port_caddr = (caddr_t)(uintptr_t)state.thread_port; - if (::ptrace(PT_THUPDATE, state_pid, thread_port_caddr, soft_signal) != 0) - error.SetError(errno, eErrorTypePOSIX); - - if (!error.Success()) { - LLDB_LOGF(log, - "::ptrace(request = PT_THUPDATE, pid = " - "0x%4.4x, tid = 0x%4.4x, signal = %i)", - state_pid, state.thread_port, soft_signal); - return error; - } - } - } - - LLDB_LOGF(log, - "::mach_msg ( msg->{bits = %#x, size = %u, remote_port " - "= %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %u, rcv_name " - "= %#x, timeout = %u, notify = %#x)", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id, - MACH_SEND_MSG | MACH_SEND_INTERRUPT, reply_msg.hdr.msgh_size, 0, - MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - - auto mach_err = - ::mach_msg(&reply_msg.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT, - reply_msg.hdr.msgh_size, 0, MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - - // Log our error if we have one. - if (error.Fail() && log) { - if (error.GetError() == MACH_SEND_INTERRUPTED) { - log->PutCString("::mach_msg() - send interrupted"); - // TODO: keep retrying to reply??? - } else if (state.task_port == inferior_task) { - LLDB_LOGF(log, - "mach_msg(): returned an error when replying " - "to a mach exception: error = %u (%s)", - error.GetError(), error.AsCString()); - } else { - LLDB_LOGF(log, "::mach_msg() - failed (child of task): %u (%s)", - error.GetError(), error.AsCString()); - } - } - - return error; -} - -#define PREV_EXC_MASK_ALL \ - (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \ - EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \ - EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \ - EXC_MASK_MACHINE) - -// Don't listen for EXC_RESOURCE, it should really get handled by the system -// handler. - -#ifndef EXC_RESOURCE -#define EXC_RESOURCE 11 -#endif - -#ifndef EXC_MASK_RESOURCE -#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE) -#endif - -#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) - -Status MachException::PortInfo::Save(task_t task) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "MachException::PortInfo::%s(task = 0x%4.4x)", __FUNCTION__, - task); - - // Be careful to be able to have debugserver built on a newer OS than what it - // is currently running on by being able to start with all exceptions and - // back off to just what is supported on the current system - mask = LLDB_EXC_MASK; - - count = (sizeof(ports) / sizeof(ports[0])); - auto mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, - behaviors, flavors); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = " - "0x%x, maskCnt => %u, ports, behaviors, flavors)", - task, mask, count); - } else { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = 0x%x, " - "maskCnt => %u, ports, behaviors, flavors) error: %u (%s)", - task, mask, count, error.GetError(), error.AsCString()); - } - } - - if ((error.GetError() == KERN_INVALID_ARGUMENT) && - (mask != PREV_EXC_MASK_ALL)) { - mask = PREV_EXC_MASK_ALL; - count = (sizeof(ports) / sizeof(ports[0])); - mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, - behaviors, flavors); - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, " - "mask = 0x%x, maskCnt => %u, ports, behaviors, " - "flavors)", - task, mask, count); - } else { - LLDB_LOGF(log, - "::task_get_exception_ports(task = 0x%4.4x, mask = " - "0x%x, maskCnt => %u, ports, behaviors, flavors) " - "error: %u (%s)", - task, mask, count, error.GetError(), error.AsCString()); - } - } - } - if (error.Fail()) { - mask = 0; - count = 0; - } - return error; -} - -Status MachException::PortInfo::Restore(task_t task) { - Status error; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "MachException::PortInfo::Restore(task = 0x%4.4x)", task); - - uint32_t i = 0; - if (count > 0) { - for (i = 0; i < count; i++) { - auto mach_err = ::task_set_exception_ports(task, masks[i], ports[i], - behaviors[i], flavors[i]); - if (mach_err) - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) { - LLDB_LOGF(log, - "::task_set_exception_ports(task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x)", - task, masks[i], ports[i], behaviors[i], flavors[i]); - } else { - LLDB_LOGF(log, - "::task_set_exception_ports(task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x): " - "error %u (%s)", - task, masks[i], ports[i], behaviors[i], flavors[i], - error.GetError(), error.AsCString()); - } - } - - // Bail if we encounter any errors - if (error.Fail()) - break; - } - } - - count = 0; - return error; -} - -const char *MachException::Name(exception_type_t exc_type) { - switch (exc_type) { - case EXC_BAD_ACCESS: - return "EXC_BAD_ACCESS"; - case EXC_BAD_INSTRUCTION: - return "EXC_BAD_INSTRUCTION"; - case EXC_ARITHMETIC: - return "EXC_ARITHMETIC"; - case EXC_EMULATION: - return "EXC_EMULATION"; - case EXC_SOFTWARE: - return "EXC_SOFTWARE"; - case EXC_BREAKPOINT: - return "EXC_BREAKPOINT"; - case EXC_SYSCALL: - return "EXC_SYSCALL"; - case EXC_MACH_SYSCALL: - return "EXC_MACH_SYSCALL"; - case EXC_RPC_ALERT: - return "EXC_RPC_ALERT"; -#ifdef EXC_CRASH - case EXC_CRASH: - return "EXC_CRASH"; -#endif - default: - break; - } - return NULL; -} diff --git a/lldb/source/Plugins/Process/Darwin/MachException.h b/lldb/source/Plugins/Process/Darwin/MachException.h deleted file mode 100644 index 18e4917..0000000 --- a/lldb/source/Plugins/Process/Darwin/MachException.h +++ /dev/null @@ -1,139 +0,0 @@ -//===-- MachException.h -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/18/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __MachException_h__ -#define __MachException_h__ - -#include -#include - -#include "lldb/Host/Debug.h" -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-types.h" - -namespace lldb_private { -namespace process_darwin { - -typedef union MachMessageTag { - mach_msg_header_t hdr; - char data[1024]; -} MachMessage; - -class MachException { -public: - struct PortInfo { - exception_mask_t mask; // the exception mask for this device which may be a - // subset of EXC_MASK_ALL... - exception_mask_t masks[EXC_TYPES_COUNT]; - mach_port_t ports[EXC_TYPES_COUNT]; - exception_behavior_t behaviors[EXC_TYPES_COUNT]; - thread_state_flavor_t flavors[EXC_TYPES_COUNT]; - mach_msg_type_number_t count; - - Status Save(task_t task); - - Status Restore(task_t task); - }; - - struct Data { - task_t task_port; - thread_t thread_port; - exception_type_t exc_type; - std::vector exc_data; - Data() - : task_port(TASK_NULL), thread_port(THREAD_NULL), exc_type(0), - exc_data() {} - - void Clear() { - task_port = TASK_NULL; - thread_port = THREAD_NULL; - exc_type = 0; - exc_data.clear(); - } - - bool IsValid() const { - return task_port != TASK_NULL && thread_port != THREAD_NULL && - exc_type != 0; - } - - // Return the SoftSignal for this MachException data, or zero if there is - // none - int SoftSignal() const { - if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && - exc_data[0] == EXC_SOFT_SIGNAL) - return static_cast(exc_data[1]); - return 0; - } - - bool IsBreakpoint() const { - return (exc_type == EXC_BREAKPOINT || - ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1)); - } - - bool GetStopInfo(ThreadStopInfo *stop_info, const UnixSignals &signals, - Stream &stream) const; - }; - - struct Message { - MachMessage exc_msg; - MachMessage reply_msg; - Data state; - - Message() : state() { - memset(&exc_msg, 0, sizeof(exc_msg)); - memset(&reply_msg, 0, sizeof(reply_msg)); - } - - bool CatchExceptionRaise(task_t task); - - Status Reply(::pid_t inferior_pid, task_t inferior_task, int signal); - - Status Receive(mach_port_t receive_port, mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port = MACH_PORT_NULL); - - void Dump(Stream &stream) const; - - typedef std::vector collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - }; - - enum { - e_actionForward, // Forward signal to inferior process - e_actionStop, // Stop when this signal is received - }; - struct Action { - task_t task_port; // Set to TASK_NULL for any TASK - thread_t thread_port; // Set to THREAD_NULL for any thread - exception_type_t exc_mask; // Mach exception mask to watch for - std::vector exc_data_mask; // Mask to apply to - // exception data, or - // empty to ignore - // exc_data value for - // exception - std::vector exc_data_value; // Value to compare - // to exception data - // after masking, or - // empty to ignore - // exc_data value - // for exception - uint8_t flags; // Action flags describing what to do with the exception - }; - - static const char *Name(exception_type_t exc_type); -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif diff --git a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp deleted file mode 100644 index 7b35f2e..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ /dev/null @@ -1,1535 +0,0 @@ -//===-- NativeProcessDarwin.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "NativeProcessDarwin.h" - -// C includes -#include -#include -#include -#include -#include -#include - -// C++ includes -// LLDB includes -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/StreamString.h" - -#include "CFBundle.h" -#include "CFString.h" -#include "DarwinProcessLauncher.h" - -#include "MachException.h" - -#include "llvm/Support/FileSystem.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; -using namespace lldb_private::darwin_process_launcher; - -// Hidden Impl - -namespace { -struct hack_task_dyld_info { - mach_vm_address_t all_image_info_addr; - mach_vm_size_t all_image_info_size; -}; -} - -// Public Static Methods - -Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, - NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - Status error; - - // Verify the working directory is valid if one was specified. - FileSpec working_dir(launch_info.GetWorkingDirectory()); - if (working_dir) { - FileInstance::Instance().Resolve(working_dir); - if (!FileSystem::Instance().IsDirectory(working_dir)) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; - } - } - - // Launch the inferior. - int pty_master_fd = -1; - LaunchFlavor launch_flavor = LaunchFlavor::Default; - - error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor); - - // Handle launch failure. - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() failed to launch process: " - "%s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Handle failure to return a pid. - if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() launch succeeded but no " - "pid was returned! Aborting.", - __FUNCTION__); - return error; - } - - // Create the Darwin native process impl. - std::shared_ptr np_darwin_sp( - new NativeProcessDarwin(launch_info.GetProcessID(), pty_master_fd)); - if (!np_darwin_sp->RegisterNativeDelegate(native_delegate)) { - native_process_sp.reset(); - error.SetErrorStringWithFormat("failed to register the native delegate"); - return error; - } - - // Finalize the processing needed to debug the launched process with a - // NativeProcessDarwin instance. - error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop); - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() aborting, failed to finalize" - " the launching of the process: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Return the process and process id to the caller through the launch args. - native_process_sp = np_darwin_sp; - return error; -} - -Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, "NativeProcessDarwin::%s(pid = %" PRIi64 ")", __FUNCTION__, - pid); - - // Retrieve the architecture for the running process. - ArchSpec process_arch; - Status error = ResolveProcessArchitecture(pid, process_arch); - if (!error.Success()) - return error; - - // TODO get attach to return this value. - const int pty_master_fd = -1; - std::shared_ptr native_process_darwin_sp( - new NativeProcessDarwin(pid, pty_master_fd)); - - if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) { - error.SetErrorStringWithFormat("failed to register the native " - "delegate"); - return error; - } - - native_process_darwin_sp->AttachToInferior(mainloop, pid, error); - if (!error.Success()) - return error; - - native_process_sp = native_process_darwin_sp; - return error; -} - -// ctor/dtor - -NativeProcessDarwin::NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd) - : NativeProcessProtocol(pid), m_task(TASK_NULL), m_did_exec(false), - m_cpu_type(0), m_exception_port(MACH_PORT_NULL), m_exc_port_info(), - m_exception_thread(nullptr), m_exception_messages_mutex(), - m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_thread_list(), - m_thread_actions(), m_waitpid_pipe(), m_waitpid_thread(nullptr), - m_waitpid_reader_handle() { - // TODO add this to the NativeProcessProtocol constructor. - m_terminal_fd = pty_master_fd; -} - -NativeProcessDarwin::~NativeProcessDarwin() {} - -// Instance methods - -Status NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, - MainLoop &main_loop) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - error = StartExceptionThread(); - if (!error.Success()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failure starting the " - "mach exception port monitor thread: %s", - __FUNCTION__, error.AsCString()); - - // Terminate the inferior process. There's nothing meaningful we can do if - // we can't receive signals and exceptions. Since we launched the process, - // it's fair game for us to kill it. - ::ptrace(PT_KILL, m_pid, 0, 0); - SetState(eStateExited); - - return error; - } - - StartSTDIOThread(); - - if (launch_flavor == LaunchFlavor::PosixSpawn) { - SetState(eStateAttaching); - errno = 0; - int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); - if (err == 0) { - // m_flags |= eMachProcessFlagsAttached; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): successfully spawned " - "process with pid %" PRIu64, - __FUNCTION__, m_pid); - } else { - error.SetErrorToErrno(); - SetState(eStateExited); - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): error: failed to " - "attach to spawned pid %" PRIu64 " (error=%d (%s))", - __FUNCTION__, m_pid, (int)error.GetError(), error.AsCString()); - return error; - } - } - - LLDB_LOGF(log, "NativeProcessDarwin::%s(): new pid is %" PRIu64 "...", - __FUNCTION__, m_pid); - - // Spawn a thread to reap our child inferior process... - error = StartWaitpidThread(main_loop); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to start waitpid() " - "thread: %s", - __FUNCTION__, error.AsCString()); - kill(SIGKILL, static_cast<::pid_t>(m_pid)); - return error; - } - - if (TaskPortForProcessID(error) == TASK_NULL) { - // We failed to get the task for our process ID which is bad. Kill our - // process; otherwise, it will be stopped at the entry point and get - // reparented to someone else and never go away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): could not get task port " - "for process, sending SIGKILL and exiting: %s", - __FUNCTION__, error.AsCString()); - kill(SIGKILL, static_cast<::pid_t>(m_pid)); - return error; - } - - // Indicate that we're stopped, as we always launch suspended. - SetState(eStateStopped); - - // Success. - return error; -} - -Status NativeProcessDarwin::SaveExceptionPortInfo() { - return m_exc_port_info.Save(m_task); -} - -bool NativeProcessDarwin::ProcessUsingSpringBoard() const { - // TODO implement flags - // return (m_flags & eMachProcessFlagsUsingSBS) != 0; - return false; -} - -bool NativeProcessDarwin::ProcessUsingBackBoard() const { - // TODO implement flags - // return (m_flags & eMachProcessFlagsUsingBKS) != 0; - return false; -} - -// Called by the exception thread when an exception has been received from our -// process. The exception message is completely filled and the exception data -// has already been copied. -void NativeProcessDarwin::ExceptionMessageReceived( - const MachException::Message &message) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - std::lock_guard locker(m_exception_messages_mutex); - if (m_exception_messages.empty()) { - // Suspend the task the moment we receive our first exception message. - SuspendTask(); - } - - // Use a locker to automatically unlock our mutex in case of exceptions Add - // the exception to our internal exception stack - m_exception_messages.push_back(message); - - LLDB_LOGF(log, "NativeProcessDarwin::%s(): new queued message count: %lu", - __FUNCTION__, m_exception_messages.size()); -} - -void *NativeProcessDarwin::ExceptionThread(void *arg) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (!arg) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot run mach exception " - "thread, mandatory process arg was null", - __FUNCTION__); - return nullptr; - } - - return reinterpret_cast(arg)->DoExceptionThread(); -} - -void *NativeProcessDarwin::DoExceptionThread() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - LLDB_LOGF(log, "NativeProcessDarwin::%s(arg=%p) starting thread...", - __FUNCTION__, this); - - pthread_setname_np("exception monitoring thread"); - - // Ensure we don't get CPU starved. - MaybeRaiseThreadPriority(); - - // We keep a count of the number of consecutive exceptions received so we - // know to grab all exceptions without a timeout. We do this to get a bunch - // of related exceptions on our exception port so we can process then - // together. When we have multiple threads, we can get an exception per - // thread and they will come in consecutively. The main loop in this thread - // can stop periodically if needed to service things related to this process. - // - // [did we lose some words here?] - // - // flag set in the options, so we will wait forever for an exception on - // 0 our exception port. After we get one exception, we then will use the - // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current - // exceptions for our process. After we have received the last pending - // exception, we will get a timeout which enables us to then notify our main - // thread that we have an exception bundle available. We then wait for the - // main thread to tell this exception thread to start trying to get - // exceptions messages again and we start again with a mach_msg read with - // infinite timeout. - // - // We choose to park a thread on this, rather than polling, because the - // polling is expensive. On devices, we need to minimize overhead caused by - // the process monitor. - uint32_t num_exceptions_received = 0; - Status error; - task_t task = m_task; - mach_msg_timeout_t periodic_timeout = 0; - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - mach_msg_timeout_t watchdog_elapsed = 0; - mach_msg_timeout_t watchdog_timeout = 60 * 1000; - ::pid_t pid = (::pid_t)process->GetID(); - CFReleaser watchdog; - - if (process->ProcessUsingSpringBoard()) { - // Request a renewal for every 60 seconds if we attached using SpringBoard. - watchdog.reset(::SBSWatchdogAssertionCreateForPID(nullptr, pid, 60)); - LLDB_LOGF(log, - "::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) " - "=> %p", - pid, watchdog.get()); - - if (watchdog.get()) { - ::SBSWatchdogAssertionRenew(watchdog.get()); - - CFTimeInterval watchdogRenewalInterval = - ::SBSWatchdogAssertionGetRenewalInterval(watchdog.get()); - LLDB_LOGF(log, - "::SBSWatchdogAssertionGetRenewalInterval(%p) => " - "%g seconds", - watchdog.get(), watchdogRenewalInterval); - if (watchdogRenewalInterval > 0.0) { - watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000; - if (watchdog_timeout > 3000) { - // Give us a second to renew our timeout. - watchdog_timeout -= 1000; - } else if (watchdog_timeout > 1000) { - // Give us a quarter of a second to renew our timeout. - watchdog_timeout -= 250; - } - } - } - if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout) - periodic_timeout = watchdog_timeout; - } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - -#ifdef WITH_BKS - CFReleaser watchdog; - if (process->ProcessUsingBackBoard()) { - ::pid_t pid = process->GetID(); - CFAllocatorRef alloc = kCFAllocatorDefault; - watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); - } -#endif // #ifdef WITH_BKS - - // Do we want to use a weak pointer to the NativeProcessDarwin here, in which - // case we can guarantee we don't whack the process monitor if we race - // between this thread and the main one on shutdown? - while (IsExceptionPortValid()) { - ::pthread_testcancel(); - - MachException::Message exception_message; - - if (num_exceptions_received > 0) { - // We don't want a timeout here, just receive as many exceptions as we - // can since we already have one. We want to get all currently available - // exceptions for this task at once. - error = exception_message.Receive( - GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); - } else if (periodic_timeout > 0) { - // We need to stop periodically in this loop, so try and get a mach - // message with a valid timeout (ms). - error = exception_message.Receive(GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT | - MACH_RCV_TIMEOUT, - periodic_timeout); - } else { - // We don't need to parse all current exceptions or stop periodically, - // just wait for an exception forever. - error = exception_message.Receive(GetExceptionPort(), - MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); - } - - if (error.Success()) { - // We successfully received an exception. - if (exception_message.CatchExceptionRaise(task)) { - ++num_exceptions_received; - ExceptionMessageReceived(exception_message); - } - } else { - if (error.GetError() == MACH_RCV_INTERRUPTED) { - // We were interrupted. - - // If we have no task port we should exit this thread, as it implies - // the inferior went down. - if (!IsExceptionPortValid()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior " - "exception port is no longer valid, " - "canceling exception thread...", - __FUNCTION__); - // Should we be setting a process state here? - break; - } - - // Make sure the inferior task is still valid. - if (IsTaskValid()) { - // Task is still ok. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): interrupted, but " - "the inferior task iss till valid, " - "continuing...", - __FUNCTION__); - continue; - } else { - // The inferior task is no longer valid. Time to exit as the process - // has gone away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior task " - "has exited, and so will we...", - __FUNCTION__); - // Does this race at all with our waitpid()? - SetState(eStateExited); - break; - } - } else if (error.GetError() == MACH_RCV_TIMED_OUT) { - // We timed out when waiting for exceptions. - - if (num_exceptions_received > 0) { - // We were receiving all current exceptions with a timeout of zero. - // It is time to go back to our normal looping mode. - num_exceptions_received = 0; - - // Notify our main thread we have a complete exception message bundle - // available. Get the possibly updated task port back from the - // process in case we exec'ed and our task port changed. - task = ExceptionMessageBundleComplete(); - - // In case we use a timeout value when getting exceptions, make sure - // our task is still valid. - if (IsTaskValid(task)) { - // Task is still ok. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): got a timeout, " - "continuing...", - __FUNCTION__); - continue; - } else { - // The inferior task is no longer valid. Time to exit as the - // process has gone away. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): the inferior " - "task has exited, and so will we...", - __FUNCTION__); - // Does this race at all with our waitpid()? - SetState(eStateExited); - break; - } - } - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - if (watchdog.get()) { - watchdog_elapsed += periodic_timeout; - if (watchdog_elapsed >= watchdog_timeout) { - LLDB_LOGF(log, "SBSWatchdogAssertionRenew(%p)", watchdog.get()); - ::SBSWatchdogAssertionRenew(watchdog.get()); - watchdog_elapsed = 0; - } - } -#endif - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): continuing after " - "receiving an unexpected error: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - // TODO: notify of error? - } - } - } - -#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) - if (watchdog.get()) { - // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel - // when we - // all are up and running on systems that support it. The SBS framework has - // a #define that will forward SBSWatchdogAssertionRelease to - // SBSWatchdogAssertionCancel for now so it should still build either way. - DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", - watchdog.get()); - ::SBSWatchdogAssertionRelease(watchdog.get()); - } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - - LLDB_LOGF(log, "NativeProcessDarwin::%s(%p): thread exiting...", __FUNCTION__, - this); - return nullptr; -} - -Status NativeProcessDarwin::StartExceptionThread() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, "NativeProcessDarwin::%s() called", __FUNCTION__); - - // Make sure we've looked up the inferior port. - TaskPortForProcessID(error); - - // Ensure the inferior task is valid. - if (!IsTaskValid()) { - error.SetErrorStringWithFormat("cannot start exception thread: " - "task 0x%4.4x is not valid", - m_task); - return error; - } - - // Get the mach port for the process monitor. - mach_port_t task_self = mach_task_self(); - - // Allocate an exception port that we will use to track our child process - auto mach_err = ::mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, - &m_exception_port); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): mach_port_allocate(" - "task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, " - "&m_exception_port) failed: %u (%s)", - __FUNCTION__, task_self, error.GetError(), error.AsCString()); - return error; - } - - // Add the ability to send messages on the new exception port - mach_err = ::mach_port_insert_right( - task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): mach_port_insert_right(" - "task_self=0x%4.4x, m_exception_port=0x%4.4x, " - "m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND) " - "failed: %u (%s)", - __FUNCTION__, task_self, m_exception_port, m_exception_port, - error.GetError(), error.AsCString()); - return error; - } - - // Save the original state of the exception ports for our child process. - error = SaveExceptionPortInfo(); - if (error.Fail() || (m_exc_port_info.mask == 0)) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): SaveExceptionPortInfo() " - "failed, cannot install exception handler: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Set the ability to get all exceptions on this port. - mach_err = ::task_set_exception_ports( - m_task, m_exc_port_info.mask, m_exception_port, - EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_set_exception_ports (task = 0x%4.4x, " - "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " - "behavior = 0x%8.8x, new_flavor = 0x%8.8x) failed: " - "%u (%s)", - m_task, m_exc_port_info.mask, m_exception_port, - (EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), THREAD_STATE_NONE, - error.GetError(), error.AsCString()); - return error; - } - - // Create the exception thread. - auto pthread_err = - ::pthread_create(&m_exception_thread, nullptr, ExceptionThread, this); - error.SetError(pthread_err, eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create Mach " - "exception-handling thread: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - } - - return error; -} - -lldb::addr_t -NativeProcessDarwin::GetDYLDAllImageInfosAddress(Status &error) const { - error.Clear(); - - struct hack_task_dyld_info dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - // Make sure that COUNT isn't bigger than our hacked up struct - // hack_task_dyld_info. If it is, then make COUNT smaller to match. - if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t))) { - count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)); - } - - TaskPortForProcessID(error); - if (error.Fail()) - return LLDB_INVALID_ADDRESS; - - auto mach_err = - ::task_info(m_task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Success()) { - // We now have the address of the all image infos structure. - return dyld_info.all_image_info_addr; - } - - // We don't have it. - return LLDB_INVALID_ADDRESS; -} - -uint32_t NativeProcessDarwin::GetCPUTypeForLocalProcess(::pid_t pid) { - int mib[CTL_MAXNAME] = { - 0, - }; - size_t len = CTL_MAXNAME; - - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl(mib, static_cast(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; -} - -uint32_t NativeProcessDarwin::GetCPUType() const { - if (m_cpu_type == 0 && m_pid != 0) - m_cpu_type = GetCPUTypeForLocalProcess(m_pid); - return m_cpu_type; -} - -task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { - // We have a complete bundle of exceptions for our child process. - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - std::lock_guard locker(m_exception_messages_mutex); - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): processing %lu exception " - "messages.", - __FUNCTION__, m_exception_messages.size()); - - if (m_exception_messages.empty()) { - // Not particularly useful... - return m_task; - } - - bool auto_resume = false; - m_did_exec = false; - - // First check for any SIGTRAP and make sure we didn't exec - const task_t task = m_task; - size_t i; - if (m_pid != 0) { - bool received_interrupt = false; - uint32_t num_task_exceptions = 0; - for (i = 0; i < m_exception_messages.size(); ++i) { - if (m_exception_messages[i].state.task_port != task) { - // This is an exception that is not for our inferior, ignore. - continue; - } - - // This is an exception for the inferior. - ++num_task_exceptions; - const int signo = m_exception_messages[i].state.SoftSignal(); - if (signo == SIGTRAP) { - // SIGTRAP could mean that we exec'ed. We need to check the - // dyld all_image_infos.infoArray to see if it is NULL and if so, say - // that we exec'ed. - const addr_t aii_addr = GetDYLDAllImageInfosAddress(error); - if (aii_addr == LLDB_INVALID_ADDRESS) - break; - - const addr_t info_array_count_addr = aii_addr + 4; - uint32_t info_array_count = 0; - size_t bytes_read = 0; - Status read_error; - read_error = ReadMemory(info_array_count_addr, // source addr - &info_array_count, // dest addr - 4, // byte count - bytes_read); // #bytes read - if (read_error.Success() && (bytes_read == 4)) { - if (info_array_count == 0) { - // We got the all infos address, and there are zero entries. We - // think we exec'd. - m_did_exec = true; - - // Force the task port to update itself in case the task port - // changed after exec - const task_t old_task = m_task; - const bool force_update = true; - const task_t new_task = TaskPortForProcessID(error, force_update); - if (old_task != new_task) { - LLDB_LOGF(log, - "exec: inferior task port changed " - "from 0x%4.4x to 0x%4.4x", - old_task, new_task); - } - } - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() warning: " - "failed to read all_image_infos." - "infoArrayCount from 0x%8.8llx", - __FUNCTION__, info_array_count_addr); - } - } else if ((m_sent_interrupt_signo != 0) && - (signo == m_sent_interrupt_signo)) { - // We just received the interrupt that we sent to ourselves. - received_interrupt = true; - } - } - - if (m_did_exec) { - cpu_type_t process_cpu_type = GetCPUTypeForLocalProcess(m_pid); - if (m_cpu_type != process_cpu_type) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): arch changed from " - "0x%8.8x to 0x%8.8x", - __FUNCTION__, m_cpu_type, process_cpu_type); - m_cpu_type = process_cpu_type; - // TODO figure out if we need to do something here. - // DNBArchProtocol::SetArchitecture (process_cpu_type); - } - m_thread_list.Clear(); - - // TODO hook up breakpoints. - // m_breakpoints.DisableAll(); - } - - if (m_sent_interrupt_signo != 0) { - if (received_interrupt) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): process " - "successfully interrupted with signal %i", - __FUNCTION__, m_sent_interrupt_signo); - - // Mark that we received the interrupt signal - m_sent_interrupt_signo = 0; - // Now check if we had a case where: - // 1 - We called NativeProcessDarwin::Interrupt() but we stopped - // for another reason. - // 2 - We called NativeProcessDarwin::Resume() (but still - // haven't gotten the interrupt signal). - // 3 - We are now incorrectly stopped because we are handling - // the interrupt signal we missed. - // 4 - We might need to resume if we stopped only with the - // interrupt signal that we never handled. - if (m_auto_resume_signo != 0) { - // Only auto_resume if we stopped with _only_ the interrupt signal. - if (num_task_exceptions == 1) { - auto_resume = true; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): auto " - "resuming due to unhandled interrupt " - "signal %i", - __FUNCTION__, m_auto_resume_signo); - } - m_auto_resume_signo = 0; - } - } else { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): didn't get signal " - "%i after MachProcess::Interrupt()", - __FUNCTION__, m_sent_interrupt_signo); - } - } - } - - // Let all threads recover from stopping and do any clean up based on the - // previous thread state (if any). - m_thread_list.ProcessDidStop(*this); - - // Let each thread know of any exceptions - for (i = 0; i < m_exception_messages.size(); ++i) { - // Let the thread list forward all exceptions on down to each thread. - if (m_exception_messages[i].state.task_port == task) { - // This exception is for our inferior. - m_thread_list.NotifyException(m_exception_messages[i].state); - } - - if (log) { - StreamString stream; - m_exception_messages[i].Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - } - - if (log) { - StreamString stream; - m_thread_list.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); - } - - bool step_more = false; - if (m_thread_list.ShouldStop(step_more) && (auto_resume == false)) { -// TODO - need to hook up event system here. !!!! -#if 0 - // Wait for the eEventProcessRunningStateChanged event to be reset - // before changing state to stopped to avoid race condition with very - // fast start/stops. - struct timespec timeout; - - //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms - DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms - m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, - &timeout); -#endif - SetState(eStateStopped); - } else { - // Resume without checking our current state. - PrivateResume(); - } - - return m_task; -} - -void NativeProcessDarwin::StartSTDIOThread() { - // TODO implement -} - -Status NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Strategy: create a thread that sits on waitpid(), waiting for the inferior - // process to die, reaping it in the process. Arrange for the thread to have - // a pipe file descriptor that it can send a byte over when the waitpid - // completes. Have the main loop have a read object for the other side of - // the pipe, and have the callback for the read do the process termination - // message sending. - - // Create a single-direction communication channel. - const bool child_inherits = false; - error = m_waitpid_pipe.CreateNew(child_inherits); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create waitpid " - "communication pipe: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // Hook up the waitpid reader callback. - - // TODO make PipePOSIX derive from IOObject. This is goofy here. - const bool transfer_ownership = false; - auto io_sp = IOObjectSP(new NativeFile(m_waitpid_pipe.GetReadFileDescriptor(), - transfer_ownership)); - m_waitpid_reader_handle = main_loop.RegisterReadObject( - io_sp, [this](MainLoopBase &) { HandleWaitpidResult(); }, error); - - // Create the thread. - auto pthread_err = - ::pthread_create(&m_waitpid_thread, nullptr, WaitpidThread, this); - error.SetError(pthread_err, eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to create waitpid " - "handling thread: %u (%s)", - __FUNCTION__, error.GetError(), error.AsCString()); - return error; - } - - return error; -} - -void *NativeProcessDarwin::WaitpidThread(void *arg) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!arg) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot run waitpid " - "thread, mandatory process arg was null", - __FUNCTION__); - return nullptr; - } - - return reinterpret_cast(arg)->DoWaitpidThread(); -} - -void NativeProcessDarwin::MaybeRaiseThreadPriority() { -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, - &thread_param) == 0) { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } -#endif -} - -void *NativeProcessDarwin::DoWaitpidThread() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (m_pid == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): inferior process ID is " - "not set, cannot waitpid on it", - __FUNCTION__); - return nullptr; - } - - // Name the thread. - pthread_setname_np("waitpid thread"); - - // Ensure we don't get CPU starved. - MaybeRaiseThreadPriority(); - - Status error; - int status = -1; - - while (1) { - // Do a waitpid. - ::pid_t child_pid = ::waitpid(m_pid, &status, 0); - if (child_pid < 0) - error.SetErrorToErrno(); - if (error.Fail()) { - if (error.GetError() == EINTR) { - // This is okay, we can keep going. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) interrupted, continuing", - __FUNCTION__, m_pid); - continue; - } - - // This error is not okay, abort. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) aborting due to error: %u (%s)", - __FUNCTION__, m_pid, error.GetError(), error.AsCString()); - break; - } - - // Log the successful result. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) => %i, status = %i", - __FUNCTION__, m_pid, child_pid, status); - - // Handle the result. - if (WIFSTOPPED(status)) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ") received a stop, continuing waitpid() loop", - __FUNCTION__, m_pid); - continue; - } else // if (WIFEXITED(status) || WIFSIGNALED(status)) - { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(pid = %" PRIu64 "): " - "waitpid thread is setting exit status for pid = " - "%i to %i", - __FUNCTION__, m_pid, child_pid, status); - - error = SendInferiorExitStatusToMainLoop(child_pid, status); - return nullptr; - } - } - - // We should never exit as long as our child process is alive. If we get - // here, something completely unexpected went wrong and we should exit. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): internal error: waitpid thread " - "exited out of its main loop in an unexpected way. pid = %" PRIu64 - ". Sending exit status of -1.", - __FUNCTION__, m_pid); - - error = SendInferiorExitStatusToMainLoop((::pid_t)m_pid, -1); - return nullptr; -} - -Status NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid, - int status) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - size_t bytes_written = 0; - - // Send the pid. - error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written); - if (error.Fail() || (bytes_written < sizeof(pid))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to write " - "waitpid exiting pid to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); - return error; - } - - // Send the status. - bytes_written = 0; - error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written); - if (error.Fail() || (bytes_written < sizeof(status))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to write " - "waitpid exit result to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); - } - return error; -} - -Status NativeProcessDarwin::HandleWaitpidResult() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Read the pid. - const bool notify_status = true; - - ::pid_t pid = -1; - size_t bytes_read = 0; - error = m_waitpid_pipe.Read(&pid, sizeof(pid), bytes_read); - if (error.Fail() || (bytes_read < sizeof(pid))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to read " - "waitpid exiting pid from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); - return error; - } - - // Read the status. - int status = -1; - error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read); - if (error.Fail() || (bytes_read < sizeof(status))) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s() - failed to read " - "waitpid exit status from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); - return error; - } - - // Notify the monitor that our state has changed. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): main loop received waitpid " - "exit status info: pid=%i (%s), status=%i", - __FUNCTION__, pid, - (pid == m_pid) ? "the inferior" : "not the inferior", status); - - SetExitStatus(WaitStatus::Decode(status), notify_status); - return error; -} - -task_t NativeProcessDarwin::TaskPortForProcessID(Status &error, - bool force) const { - if ((m_task == TASK_NULL) || force) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (m_pid == LLDB_INVALID_PROCESS_ID) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): cannot get task due " - "to invalid pid", - __FUNCTION__); - return TASK_NULL; - } - - const uint32_t num_retries = 10; - const uint32_t usec_interval = 10000; - - mach_port_t task_self = mach_task_self(); - task_t task = TASK_NULL; - - for (uint32_t i = 0; i < num_retries; i++) { - kern_return_t err = ::task_for_pid(task_self, m_pid, &task); - if (err == 0) { - // Succeeded. Save and return it. - error.Clear(); - m_task = task; - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): ::task_for_pid(" - "stub_port = 0x%4.4x, pid = %llu, &task) " - "succeeded: inferior task port = 0x%4.4x", - __FUNCTION__, task_self, m_pid, m_task); - return m_task; - } else { - // Failed to get the task for the inferior process. - error.SetError(err, eErrorTypeMachKernel); - if (log) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): ::task_for_pid(" - "stub_port = 0x%4.4x, pid = %llu, &task) " - "failed, err = 0x%8.8x (%s)", - __FUNCTION__, task_self, m_pid, err, error.AsCString()); - } - } - - // Sleep a bit and try again - ::usleep(usec_interval); - } - - // We failed to get the task for the inferior process. Ensure that it is - // cleared out. - m_task = TASK_NULL; - } - return m_task; -} - -void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, - Status &error) { - error.SetErrorString("TODO: implement"); -} - -Status NativeProcessDarwin::PrivateResume() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - std::lock_guard locker(m_exception_messages_mutex); - m_auto_resume_signo = m_sent_interrupt_signo; - - if (log) { - if (m_auto_resume_signo) - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): task 0x%x resuming (with " - "unhandled interrupt signal %i)...", - __FUNCTION__, m_task, m_auto_resume_signo); - else - LLDB_LOGF(log, "NativeProcessDarwin::%s(): task 0x%x resuming...", - __FUNCTION__, m_task); - } - - error = ReplyToAllExceptions(); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): aborting, failed to " - "reply to exceptions: %s", - __FUNCTION__, error.AsCString()); - return error; - } - // bool stepOverBreakInstruction = step; - - // Let the thread prepare to resume and see if any threads want us to step - // over a breakpoint instruction (ProcessWillResume will modify the value of - // stepOverBreakInstruction). - m_thread_list.ProcessWillResume(*this, m_thread_actions); - - // Set our state accordingly - if (m_thread_actions.NumActionsWithState(eStateStepping)) - SetState(eStateStepping); - else - SetState(eStateRunning); - - // Now resume our task. - error = ResumeTask(); - return error; -} - -Status NativeProcessDarwin::ReplyToAllExceptions() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - - TaskPortForProcessID(error); - if (error.Fail()) { - LLDB_LOGF(log, "NativeProcessDarwin::%s(): no task port, aborting", - __FUNCTION__); - return error; - } - - std::lock_guard locker(m_exception_messages_mutex); - if (m_exception_messages.empty()) { - // We're done. - return error; - } - - size_t index = 0; - for (auto &message : m_exception_messages) { - if (log) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): replying to exception " - "%zu...", - __FUNCTION__, index++); - } - - int thread_reply_signal = 0; - - const tid_t tid = - m_thread_list.GetThreadIDByMachPortNumber(message.state.thread_port); - const ResumeAction *action = nullptr; - if (tid != LLDB_INVALID_THREAD_ID) - action = m_thread_actions.GetActionForThread(tid, false); - - if (action) { - thread_reply_signal = action->signal; - if (thread_reply_signal) - m_thread_actions.SetSignalHandledForThread(tid); - } - - error = message.Reply(m_pid, m_task, thread_reply_signal); - if (error.Fail() && log) { - // We log any error here, but we don't stop the exception response - // handling. - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to reply to " - "exception: %s", - __FUNCTION__, error.AsCString()); - error.Clear(); - } - } - - // Erase all exception message as we should have used and replied to them all - // already. - m_exception_messages.clear(); - return error; -} - -Status NativeProcessDarwin::ResumeTask() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - TaskPortForProcessID(error); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to get task port " - "for process when attempting to resume: %s", - __FUNCTION__, error.AsCString()); - return error; - } - if (m_task == TASK_NULL) { - error.SetErrorString("task port retrieval succeeded but task port is " - "null when attempting to resume the task"); - return error; - } - - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): requesting resume of task " - "0x%4.4x", - __FUNCTION__, m_task); - - // Get the BasicInfo struct to verify that we're suspended before we try to - // resume the task. - struct task_basic_info task_info; - error = GetTaskBasicInfo(m_task, &task_info); - if (error.Fail()) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): failed to get task " - "BasicInfo when attempting to resume: %s", - __FUNCTION__, error.AsCString()); - return error; - } - - // task_resume isn't counted like task_suspend calls are, so if the task is - // not suspended, don't try and resume it since it is already running - if (task_info.suspend_count > 0) { - auto mach_err = ::task_resume(m_task); - error.SetError(mach_err, eErrorTypeMachKernel); - if (log) { - if (error.Success()) - LLDB_LOGF(log, "::task_resume(target_task = 0x%4.4x): success", m_task); - else - LLDB_LOGF(log, "::task_resume(target_task = 0x%4.4x) error: %s", m_task, - error.AsCString()); - } - } else { - LLDB_LOGF(log, - "::task_resume(target_task = 0x%4.4x): ignored, " - "already running", - m_task); - } - - return error; -} - -bool NativeProcessDarwin::IsTaskValid() const { - if (m_task == TASK_NULL) - return false; - - struct task_basic_info task_info; - return GetTaskBasicInfo(m_task, &task_info).Success(); -} - -bool NativeProcessDarwin::IsTaskValid(task_t task) const { - if (task == TASK_NULL) - return false; - - struct task_basic_info task_info; - return GetTaskBasicInfo(task, &task_info).Success(); -} - -mach_port_t NativeProcessDarwin::GetExceptionPort() const { - return m_exception_port; -} - -bool NativeProcessDarwin::IsExceptionPortValid() const { - return MACH_PORT_VALID(m_exception_port); -} - -Status -NativeProcessDarwin::GetTaskBasicInfo(task_t task, - struct task_basic_info *info) const { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Validate args. - if (info == NULL) { - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): mandatory " - "info arg is null", - __FUNCTION__); - return error; - } - - // Grab the task if we don't already have it. - if (task == TASK_NULL) { - error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): given task " - "is invalid", - __FUNCTION__); - } - - mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; - auto err = ::task_info(m_task, TASK_BASIC_INFO, (task_info_t)info, &count); - error.SetError(err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_info(target_task = 0x%4.4x, " - "flavor = TASK_BASIC_INFO, task_info_out => %p, " - "task_info_outCnt => %u) failed: %u (%s)", - m_task, info, count, error.GetError(), error.AsCString()); - return error; - } - - Log *verbose_log( - GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (verbose_log) { - float user = (float)info->user_time.seconds + - (float)info->user_time.microseconds / 1000000.0f; - float system = (float)info->user_time.seconds + - (float)info->user_time.microseconds / 1000000.0f; - verbose_LLDB_LOGF(log, - "task_basic_info = { suspend_count = %i, " - "virtual_size = 0x%8.8llx, resident_size = " - "0x%8.8llx, user_time = %f, system_time = %f }", - info->suspend_count, (uint64_t)info->virtual_size, - (uint64_t)info->resident_size, user, system); - } - return error; -} - -Status NativeProcessDarwin::SuspendTask() { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (m_task == TASK_NULL) { - error.SetErrorString("task port is null, cannot suspend task"); - LLDB_LOGF(log, "NativeProcessDarwin::%s() failed: %s", __FUNCTION__, - error.AsCString()); - return error; - } - - auto mach_err = ::task_suspend(m_task); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail() && log) - LLDB_LOGF(log, "::task_suspend(target_task = 0x%4.4x)", m_task); - - return error; -} - -Status NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) { - Status error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - LLDB_LOGF(log, "NativeProcessDarwin::%s() called", __FUNCTION__); - - if (CanResume()) { - m_thread_actions = resume_actions; - error = PrivateResume(); - return error; - } - - auto state = GetState(); - if (state == eStateRunning) { - LLDB_LOGF(log, - "NativeProcessDarwin::%s(): task 0x%x is already " - "running, ignoring...", - __FUNCTION__, TaskPortForProcessID(error)); - return error; - } - - // We can't resume from this state. - error.SetErrorStringWithFormat("task 0x%x has state %s, can't resume", - TaskPortForProcessID(error), - StateAsCString(state)); - return error; -} - -Status NativeProcessDarwin::Halt() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Detach() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Signal(int signo) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Interrupt() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::Kill() { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, - size_t size, size_t &bytes_read) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, - size_t size, - size_t &bytes_read) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf, - size_t size, size_t &bytes_written) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -lldb::addr_t NativeProcessDarwin::GetSharedLibraryInfoAddress() { - return LLDB_INVALID_ADDRESS; -} - -size_t NativeProcessDarwin::UpdateThreads() { return 0; } - -bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const { - return false; -} - -Status NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -void NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) {} - -Status NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -Status NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} - -// NativeProcessProtocol protected interface -Status NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode( - size_t trap_opcode_size_hint, size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) { - Status error; - error.SetErrorString("TODO: implement"); - return error; -} diff --git a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h deleted file mode 100644 index 6741d4dd..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h +++ /dev/null @@ -1,337 +0,0 @@ -//===-- NativeProcessDarwin.h --------------------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef NativeProcessDarwin_h -#define NativeProcessDarwin_h - -// NOTE: this code should only be compiled on Apple Darwin systems. It is -// not cross-platform code and is not intended to build on any other platform. -// Therefore, platform-specific headers and code are okay here. - -// C includes -#include - -// C++ includes -#include -#include - -#include "lldb/Host/Debug.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/Pipe.h" -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/lldb-types.h" - -#include "LaunchFlavor.h" -#include "MachException.h" -#include "NativeThreadDarwin.h" -#include "NativeThreadListDarwin.h" - -namespace lldb_private { -class Status; -class Scalar; - -namespace process_darwin { - -/// \class NativeProcessDarwin -/// Manages communication with the inferior (debugee) process. -/// -/// Upon construction, this class prepares and launches an inferior process -/// for debugging. -/// -/// Changes in the inferior process state are broadcasted. -class NativeProcessDarwin : public NativeProcessProtocol { - friend Status NativeProcessProtocol::Launch( - ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - - friend Status NativeProcessProtocol::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop, NativeProcessProtocolSP &process_sp); - -public: - ~NativeProcessDarwin() override; - - // NativeProcessProtocol Interface - Status Resume(const ResumeActionList &resume_actions) override; - - Status Halt() override; - - Status Detach() override; - - Status Signal(int signo) override; - - Status Interrupt() override; - - Status Kill() override; - - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) override; - - Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, - size_t &bytes_written) override; - - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Status DeallocateMemory(lldb::addr_t addr) override; - - lldb::addr_t GetSharedLibraryInfoAddress() override; - - size_t UpdateThreads() override; - - bool GetArchitecture(ArchSpec &arch) const override; - - Status SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) override; - - void DoStopIDBumped(uint32_t newBumpId) override; - - Status GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) override; - - Status GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) override; - - NativeThreadDarwinSP GetThreadByID(lldb::tid_t id); - - task_t GetTask() const { return m_task; } - - // Interface used by NativeRegisterContext-derived classes. - static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, - void *data = nullptr, size_t data_size = 0, - long *result = nullptr); - - bool SupportHardwareSingleStepping() const; - -protected: - // NativeProcessProtocol protected interface - Status - GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, - size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) override; - -private: - /// Mach task-related Member Variables - - // The task port for the inferior process. - mutable task_t m_task; - - // True if the inferior process did an exec since we started - // monitoring it. - bool m_did_exec; - - // The CPU type of this process. - mutable cpu_type_t m_cpu_type; - - /// Exception/Signal Handling Member Variables - - // Exception port on which we will receive child exceptions - mach_port_t m_exception_port; - - // Saved state of the child exception port prior to us installing - // our own intercepting port. - MachException::PortInfo m_exc_port_info; - - // The thread that runs the Mach exception read and reply handler. - pthread_t m_exception_thread; - - // TODO see if we can remove this if we get the exception collection - // and distribution to happen in a single-threaded fashion. - std::recursive_mutex m_exception_messages_mutex; - - // A collection of exception messages caught when listening to the - // exception port. - MachException::Message::collection m_exception_messages; - - // When we call MachProcess::Interrupt(), we want to send this - // signal (if non-zero). - int m_sent_interrupt_signo; - - // If we resume the process and still haven't received our - // interrupt signal (if this is non-zero). - int m_auto_resume_signo; - - /// Thread-related Member Variables - NativeThreadListDarwin m_thread_list; - ResumeActionList m_thread_actions; - - /// Process Lifetime Member Variable - - // The pipe over which the waitpid thread and the main loop will - // communicate. - Pipe m_waitpid_pipe; - - // The thread that runs the waitpid handler. - pthread_t m_waitpid_thread; - - // waitpid reader callback handle. - MainLoop::ReadHandleUP m_waitpid_reader_handle; - - // Private Instance Methods - NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd); - - /// Finalize the launch. - /// - /// This method associates the NativeProcessDarwin instance with the host - /// process that was just launched. It peforms actions like attaching a - /// listener to the inferior exception port, ptracing the process, and the - /// like. - /// - /// \param[in] launch_flavor - /// The launch flavor that was used to launch the process. - /// - /// \param[in] main_loop - /// The main loop that will run the process monitor. Work - /// that needs to be done (e.g. reading files) gets registered - /// here along with callbacks to process the work. - /// - /// \return - /// Any error that occurred during the aforementioned - /// operations. Failure here will force termination of the - /// launched process and debugging session. - Status FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop); - - Status SaveExceptionPortInfo(); - - void ExceptionMessageReceived(const MachException::Message &message); - - void MaybeRaiseThreadPriority(); - - Status StartExceptionThread(); - - Status SendInferiorExitStatusToMainLoop(::pid_t pid, int status); - - Status HandleWaitpidResult(); - - bool ProcessUsingSpringBoard() const; - - bool ProcessUsingBackBoard() const; - - static void *ExceptionThread(void *arg); - - void *DoExceptionThread(); - - lldb::addr_t GetDYLDAllImageInfosAddress(Status &error) const; - - static uint32_t GetCPUTypeForLocalProcess(::pid_t pid); - - uint32_t GetCPUType() const; - - task_t ExceptionMessageBundleComplete(); - - void StartSTDIOThread(); - - Status StartWaitpidThread(MainLoop &main_loop); - - static void *WaitpidThread(void *arg); - - void *DoWaitpidThread(); - - task_t TaskPortForProcessID(Status &error, bool force = false) const; - - /// Attaches to an existing process. Forms the implementation of - /// Process::DoAttach. - void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); - - ::pid_t Attach(lldb::pid_t pid, Status &error); - - Status PrivateResume(); - - Status ReplyToAllExceptions(); - - Status ResumeTask(); - - bool IsTaskValid() const; - - bool IsTaskValid(task_t task) const; - - mach_port_t GetExceptionPort() const; - - bool IsExceptionPortValid() const; - - Status GetTaskBasicInfo(task_t task, struct task_basic_info *info) const; - - Status SuspendTask(); - - static Status SetDefaultPtraceOpts(const lldb::pid_t); - - static void *MonitorThread(void *baton); - - void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status); - - void WaitForNewThread(::pid_t tid); - - void MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin &thread); - - void MonitorTrace(NativeThreadDarwin &thread); - - void MonitorBreakpoint(NativeThreadDarwin &thread); - - void MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t wp_index); - - void MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread, - bool exited); - - Status SetupSoftwareSingleStepping(NativeThreadDarwin &thread); - - bool HasThreadNoLock(lldb::tid_t thread_id); - - bool StopTrackingThread(lldb::tid_t thread_id); - - NativeThreadDarwinSP AddThread(lldb::tid_t thread_id); - - Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); - - Status FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread); - - /// Writes a siginfo_t structure corresponding to the given thread - /// ID to the memory region pointed to by \p siginfo. - Status GetSignalInfo(lldb::tid_t tid, void *siginfo); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread ID to the memory pointed to by @p - /// message. - Status GetEventMessage(lldb::tid_t tid, unsigned long *message); - - void NotifyThreadDeath(lldb::tid_t tid); - - Status Detach(lldb::tid_t tid); - - // This method is requests a stop on all threads which are still - // running. It sets up a deferred delegate notification, which will - // fire once threads report as stopped. The triggerring_tid will be - // set as the current thread (main stop reason). - void StopRunningThreads(lldb::tid_t triggering_tid); - - // Notify the delegate if all threads have stopped. - void SignalIfAllThreadsStopped(); - - // Resume the given thread, optionally passing it the given signal. - // The type of resume operation (continue, single-step) depends on - // the state parameter. - Status ResumeThread(NativeThreadDarwin &thread, lldb::StateType state, - int signo); - - void ThreadWasCreated(NativeThreadDarwin &thread); - - void SigchldHandler(); -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif /* NativeProcessDarwin_h */ diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp deleted file mode 100644 index 4cfb463..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp +++ /dev/null @@ -1,281 +0,0 @@ -//===-- NativeThreadDarwin.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadDarwin.h" - -// C includes -#include - -// LLDB includes -#include "lldb/Utility/Stream.h" - -#include "NativeProcessDarwin.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -uint64_t NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( - ::thread_t mach_port_id) { - thread_identifier_info_data_t tident; - mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; - - auto mach_err = ::thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, - (thread_info_t)&tident, &tident_count); - if (mach_err != KERN_SUCCESS) { - // When we fail to get thread info for the supposed port, assume it is - // really a globally unique thread id already, or return the best thing we - // can, which is the thread port. - return mach_port_id; - } - return tident.thread_id; -} - -NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process, - bool is_64_bit, - lldb::tid_t unique_thread_id, - ::thread_t mach_thread_port) - : NativeThreadProtocol(process, unique_thread_id), - m_mach_thread_port(mach_thread_port), m_basic_info(), - m_proc_threadinfo() {} - -bool NativeThreadDarwin::GetIdentifierInfo() { - // Don't try to get the thread info once and cache it for the life of the - // thread. It changes over time, for instance if the thread name changes, - // then the thread_handle also changes... So you have to refetch it every - // time. - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - kern_return_t kret = ::thread_info(m_mach_thread_port, THREAD_IDENTIFIER_INFO, - (thread_info_t)&m_ident_info, &count); - return kret == KERN_SUCCESS; - - return false; -} - -std::string NativeThreadDarwin::GetName() { - std::string name; - - if (GetIdentifierInfo()) { - auto process_sp = GetProcess(); - if (!process_sp) { - name = ""; - return name; - } - - int len = ::proc_pidinfo(process_sp->GetID(), PROC_PIDTHREADINFO, - m_ident_info.thread_handle, &m_proc_threadinfo, - sizeof(m_proc_threadinfo)); - - if (len && m_proc_threadinfo.pth_name[0]) - name = m_proc_threadinfo.pth_name; - } - return name; -} - -lldb::StateType NativeThreadDarwin::GetState() { - // TODO implement - return eStateInvalid; -} - -bool NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, - std::string &description) { - // TODO implement - return false; -} - -NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() { - // TODO implement - return NativeRegisterContextSP(); -} - -Status NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags, bool hardware) { - Status error; - error.SetErrorString("not yet implemented"); - return error; -} - -Status NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) { - Status error; - error.SetErrorString("not yet implemented"); - return error; -} - -void NativeThreadDarwin::Dump(Stream &stream) const { -// This is what we really want once we have the thread class wired up. -#if 0 - DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", - index, - m_seq_id, - m_unique_id, - GetPC(INVALID_NUB_ADDRESS), - GetSP(INVALID_NUB_ADDRESS), - m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, - m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, - m_basic_info.cpu_usage, - m_basic_info.policy, - m_basic_info.run_state, - thread_run_state, - m_basic_info.flags, - m_basic_info.suspend_count, m_suspend_count, - m_basic_info.sleep_time); - -#else - // Here's all we have right now. - stream.Printf("tid: 0x%8.8" PRIx64 ", thread port: 0x%4.4x", GetID(), - m_mach_thread_port); -#endif -} - -bool NativeThreadDarwin::NotifyException(MachException::Data &exc) { -// TODO implement this. -#if 0 - // Allow the arch specific protocol to process (MachException::Data &)exc - // first before possible reassignment of m_stop_exception with exc. See - // also MachThread::GetStopException(). - bool handled = m_arch_up->NotifyException(exc); - - if (m_stop_exception.IsValid()) - { - // We may have more than one exception for a thread, but we need to - // only remember the one that we will say is the reason we stopped. We - // may have been single stepping and also gotten a signal exception, so - // just remember the most pertinent one. - if (m_stop_exception.IsBreakpoint()) - m_stop_exception = exc; - } - else - { - m_stop_exception = exc; - } - - return handled; -#else - // Pretend we handled it. - return true; -#endif -} - -bool NativeThreadDarwin::ShouldStop(bool &step_more) const { -// TODO: implement this -#if 0 - // See if this thread is at a breakpoint? - DNBBreakpoint *bp = CurrentBreakpoint(); - - if (bp) - { - // This thread is sitting at a breakpoint, ask the breakpoint if we - // should be stopping here. - return true; - } - else - { - if (m_arch_up->StepNotComplete()) - { - step_more = true; - return false; - } - // The thread state is used to let us know what the thread was trying - // to do. MachThread::ThreadWillResume() will set the thread state to - // various values depending if the thread was the current thread and if - // it was to be single stepped, or resumed. - if (GetState() == eStateRunning) - { - // If our state is running, then we should continue as we are in - // the process of stepping over a breakpoint. - return false; - } - else - { - // Stop if we have any kind of valid exception for this thread. - if (GetStopException().IsValid()) - return true; - } - } - return false; -#else - return false; -#endif -} - -void NativeThreadDarwin::ThreadDidStop() { -// TODO implement this. -#if 0 - // This thread has existed prior to resuming under debug nub control, and - // has just been stopped. Do any cleanup that needs to be done after - // running. - - // The thread state and breakpoint will still have the same values as they - // had prior to resuming the thread, so it makes it easy to check if we - // were trying to step a thread, or we tried to resume while being at a - // breakpoint. - - // When this method gets called, the process state is still in the state it - // was in while running so we can act accordingly. - m_arch_up->ThreadDidStop(); - - - // We may have suspended this thread so the primary thread could step - // without worrying about race conditions, so lets restore our suspend - // count. - RestoreSuspendCountAfterStop(); - - // Update the basic information for a thread - MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); - - if (m_basic_info.suspend_count > 0) - SetState(eStateSuspended); - else - SetState(eStateStopped); -#endif -} - -bool NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread) { - return thread != (::thread_t)(0); -} - -const struct thread_basic_info *NativeThreadDarwin::GetBasicInfo() const { - if (GetBasicInfo(m_mach_thread_port, &m_basic_info)) - return &m_basic_info; - return NULL; -} - -bool NativeThreadDarwin::GetBasicInfo(::thread_t thread, - struct thread_basic_info *basicInfoPtr) { - if (MachPortNumberIsValid(thread)) { - unsigned int info_count = THREAD_BASIC_INFO_COUNT; - kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, - (thread_info_t)basicInfoPtr, &info_count); - if (err == KERN_SUCCESS) - return true; - } - ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); - return false; -} - -bool NativeThreadDarwin::IsUserReady() const { - if (m_basic_info.run_state == 0) - GetBasicInfo(); - - switch (m_basic_info.run_state) { - default: - case TH_STATE_UNINTERRUPTIBLE: - break; - - case TH_STATE_RUNNING: - case TH_STATE_STOPPED: - case TH_STATE_WAITING: - case TH_STATE_HALTED: - return true; - } - return false; -} - -NativeProcessDarwinSP NativeThreadDarwin::GetNativeProcessDarwinSP() { - return std::static_pointer_cast(GetProcess()); -} diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h deleted file mode 100644 index 616a9a7..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h +++ /dev/null @@ -1,165 +0,0 @@ -//===-- NativeThreadDarwin.h ---------------------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef NativeThreadDarwin_H -#define NativeThreadDarwin_H - -// C includes -#include -#include -#include - -// C++ includes -#include -#include -#include - -// LLDB includes -#include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/lldb-private-forward.h" - -#include "MachException.h" - -namespace lldb_private { -namespace process_darwin { - -class NativeProcessDarwin; -using NativeProcessDarwinSP = std::shared_ptr; - -class NativeThreadListDarwin; - -class NativeThreadDarwin : public NativeThreadProtocol { - friend class NativeProcessDarwin; - friend class NativeThreadListDarwin; - -public: - static uint64_t - GetGloballyUniqueThreadIDForMachPortID(::thread_t mach_port_id); - - NativeThreadDarwin(NativeProcessDarwin *process, bool is_64_bit, - lldb::tid_t unique_thread_id = 0, - ::thread_t mach_thread_port = 0); - - // NativeThreadProtocol Interface - std::string GetName() override; - - lldb::StateType GetState() override; - - bool GetStopReason(ThreadStopInfo &stop_info, - std::string &description) override; - - NativeRegisterContextSP GetRegisterContext() override; - - Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, - bool hardware) override; - - Status RemoveWatchpoint(lldb::addr_t addr) override; - - // New methods that are fine for others to call. - void Dump(Stream &stream) const; - -private: - // Interface for friend classes - - /// Resumes the thread. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status Resume(uint32_t signo); - - /// Single steps the thread. If \p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status SingleStep(uint32_t signo); - - bool NotifyException(MachException::Data &exc); - - bool ShouldStop(bool &step_more) const; - - void ThreadDidStop(); - - void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); - - /// Return true if the thread is stopped. - /// If stopped by a signal, indicate the signo in the signo - /// argument. Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. - bool IsStopped(int *signo); - - const struct thread_basic_info *GetBasicInfo() const; - - static bool GetBasicInfo(::thread_t thread, - struct thread_basic_info *basicInfoPtr); - - bool IsUserReady() const; - - void SetStoppedByExec(); - - void SetStoppedByBreakpoint(); - - void SetStoppedByWatchpoint(uint32_t wp_index); - - bool IsStoppedAtBreakpoint(); - - bool IsStoppedAtWatchpoint(); - - void SetStoppedByTrace(); - - void SetStoppedWithNoReason(); - - void SetExited(); - - Status RequestStop(); - - /// Return the mach thread port number for this thread. - /// - /// \return - /// The mach port number for this thread. Returns NULL_THREAD - /// when the thread is invalid. - thread_t GetMachPortNumber() const { return m_mach_thread_port; } - - static bool MachPortNumberIsValid(::thread_t thread); - - // Private interface - bool GetIdentifierInfo(); - - void MaybeLogStateChange(lldb::StateType new_state); - - NativeProcessDarwinSP GetNativeProcessDarwinSP(); - - void SetStopped(); - - inline void MaybePrepareSingleStepWorkaround(); - - inline void MaybeCleanupSingleStepWorkaround(); - - // Member Variables - - // The mach thread port for the thread. - ::thread_t m_mach_thread_port; - - // The most recently-retrieved thread basic info. - mutable ::thread_basic_info m_basic_info; - - struct proc_threadinfo m_proc_threadinfo; - - thread_identifier_info_data_t m_ident_info; - -#if 0 - lldb::StateType m_state; - ThreadStopInfo m_stop_info; - NativeRegisterContextSP m_reg_context_sp; - std::string m_stop_description; - using WatchpointIndexMap = std::map; - WatchpointIndexMap m_watchpoint_index_map; - // cpu_set_t m_original_cpu_set; // For single-step workaround. -#endif -}; - -typedef std::shared_ptr NativeThreadDarwinSP; - -} // namespace process_darwin -} // namespace lldb_private - -#endif // #ifndef NativeThreadDarwin_H diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp deleted file mode 100644 index 890f5f6..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp +++ /dev/null @@ -1,701 +0,0 @@ -//===-- NativeThreadListDarwin.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/19/07. -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadListDarwin.h" - -// C includes -#include -#include -#include - -// LLDB includes -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/Stream.h" -#include "lldb/lldb-enumerations.h" - -#include "NativeProcessDarwin.h" -#include "NativeThreadDarwin.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_darwin; - -NativeThreadListDarwin::NativeThreadListDarwin() - : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} - -NativeThreadListDarwin::~NativeThreadListDarwin() {} - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 -nub_state_t -NativeThreadListDarwin::GetState(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetState(); - return eStateInvalid; -} - -const char * -NativeThreadListDarwin::GetName (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetName(); - return NULL; -} -#endif - -// TODO: figure out if we need to add this to NativeThreadDarwin yet. -#if 0 -ThreadInfo::QoS -NativeThreadListDarwin::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 -NativeThreadListDarwin::GetPThreadT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetPThreadT(); - return INVALID_NUB_ADDRESS; -} - -nub_addr_t -NativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetDispatchQueueT(); - return INVALID_NUB_ADDRESS; -} - -nub_addr_t -NativeThreadListDarwin::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; -} -#endif - -// TODO implement these -#if 0 -nub_thread_t -NativeThreadListDarwin::SetCurrentThread(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - { - m_current_thread = thread_sp; - return tid; - } - return INVALID_NUB_THREAD; -} - - -bool -NativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetStopException().GetStopInfo(stop_info); - return false; -} - -bool -NativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) -{ - thread_t mach_port_number = GetMachPortNumberByThreadID (tid); - - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; -} - -void -NativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - thread_sp->GetStopException().DumpStopReason(); -} - -const char * -NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetBasicInfoAsString(); - return NULL; -} - -#endif - -NativeThreadDarwinSP -NativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const { - std::lock_guard locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetID() == tid)) - return thread_sp; - } - return NativeThreadDarwinSP(); -} - -NativeThreadDarwinSP NativeThreadListDarwin::GetThreadByMachPortNumber( - ::thread_t mach_port_number) const { - std::lock_guard locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) - return thread_sp; - } - return NativeThreadDarwinSP(); -} - -lldb::tid_t NativeThreadListDarwin::GetThreadIDByMachPortNumber( - ::thread_t mach_port_number) const { - std::lock_guard locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) - return thread_sp->GetID(); - } - return LLDB_INVALID_THREAD_ID; -} - -// TODO implement -#if 0 -thread_t -NativeThreadListDarwin::GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->ThreadID() == globally_unique_id) - { - return m_threads[idx]->MachPortNumber(); - } - } - return 0; -} - -bool -NativeThreadListDarwin::GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterValue(set, reg, reg_value); - - return false; -} - -bool -NativeThreadListDarwin::SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterValue(set, reg, reg_value); - - return false; -} - -nub_size_t -NativeThreadListDarwin::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterContext (buf, buf_len); - return 0; -} - -nub_size_t -NativeThreadListDarwin::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterContext (buf, buf_len); - return 0; -} - -uint32_t -NativeThreadListDarwin::SaveRegisterState (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SaveRegisterState (); - return 0; -} - -bool -NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->RestoreRegisterState (save_id); - return 0; -} -#endif - -size_t NativeThreadListDarwin::GetNumberOfThreads() const { - std::lock_guard locker(m_threads_mutex); - return static_cast(m_threads.size()); -} - -// TODO implement -#if 0 -nub_thread_t -NativeThreadListDarwin::ThreadIDAtIndex (nub_size_t idx) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (idx < m_threads.size()) - return m_threads[idx]->ThreadID(); - return INVALID_NUB_THREAD; -} - -nub_thread_t -NativeThreadListDarwin::CurrentThreadID ( ) -{ - MachThreadSP thread_sp; - CurrentThread(thread_sp); - if (thread_sp.get()) - return thread_sp->ThreadID(); - return INVALID_NUB_THREAD; -} - -#endif - -bool NativeThreadListDarwin::NotifyException(MachException::Data &exc) { - auto thread_sp = GetThreadByMachPortNumber(exc.thread_port); - if (thread_sp) { - thread_sp->NotifyException(exc); - return true; - } - return false; -} - -void NativeThreadListDarwin::Clear() { - std::lock_guard locker(m_threads_mutex); - m_threads.clear(); -} - -uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, - bool update, - collection *new_threads) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - - std::lock_guard locker(m_threads_mutex); - LLDB_LOGF(log, - "NativeThreadListDarwin::%s() (pid = %" PRIu64 ", update = " - "%u) process stop count = %u", - __FUNCTION__, process.GetID(), update, process.GetStopID()); - - if (process.GetStopID() == 0) { - // On our first stop, we'll record details like 32/64 bitness and select - // the proper architecture implementation. - // - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)process.GetID()}; - - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if ((sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, - &bufsize, NULL, 0) == 0) && - (bufsize > 0)) { - if (processInfo.kp_proc.p_flag & P_LP64) - m_is_64_bit = true; - } - -// TODO implement architecture selection and abstraction. -#if 0 -#if defined(__i386__) || defined(__x86_64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); -#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); -#endif -#endif - } - - if (m_threads.empty() || update) { - thread_array_t thread_list = nullptr; - mach_msg_type_number_t thread_list_count = 0; - task_t task = process.GetTask(); - - Status error; - auto mach_err = ::task_threads(task, &thread_list, &thread_list_count); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) { - LLDB_LOGF(log, - "::task_threads(task = 0x%4.4x, thread_list => %p, " - "thread_list_count => %u) failed: %u (%s)", - task, thread_list, thread_list_count, error.GetError(), - error.AsCString()); - return 0; - } - - if (thread_list_count > 0) { - collection currThreads; - size_t idx; - // Iterator through the current thread list and see which threads we - // already have in our list (keep them), which ones we don't (add them), - // and which ones are not around anymore (remove them). - for (idx = 0; idx < thread_list_count; ++idx) { - // Get the Mach thread port. - const ::thread_t mach_port_num = thread_list[idx]; - - // Get the unique thread id for the mach port number. - uint64_t unique_thread_id = - NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( - mach_port_num); - - // Retrieve the thread if it exists. - auto thread_sp = GetThreadByID(unique_thread_id); - if (thread_sp) { - // We are already tracking it. Keep the existing native thread - // instance. - currThreads.push_back(thread_sp); - } else { - // We don't have a native thread instance for this thread. Create it - // now. - thread_sp.reset(new NativeThreadDarwin( - &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 before - // we add this thread to our list... - if (thread_sp->IsUserReady()) { - if (new_threads) - new_threads->push_back(thread_sp); - - currThreads.push_back(thread_sp); - } - } - } - - m_threads.swap(currThreads); - m_current_thread.reset(); - - // Free the vm memory given to us by ::task_threads() - vm_size_t thread_list_size = - (vm_size_t)(thread_list_count * sizeof(::thread_t)); - ::vm_deallocate(::mach_task_self(), (vm_address_t)thread_list, - thread_list_size); - } - } - return static_cast(m_threads.size()); -} - -// TODO implement -#if 0 - -void -NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) -{ - // locker will keep a mutex locked until it goes out of scope - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (m_current_thread.get() == NULL) - { - // Figure out which thread is going to be our current thread. This is - // currently done by finding the first thread in the list that has a - // valid exception. - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().IsValid()) - { - m_current_thread = m_threads[idx]; - break; - } - } - } - thread_sp = m_current_thread; -} - -#endif - -void NativeThreadListDarwin::Dump(Stream &stream) const { - bool first = true; - - std::lock_guard locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp) { - // Handle newlines between thread entries. - if (first) - first = false; - else - stream.PutChar('\n'); - thread_sp->Dump(stream); - } - } -} - -void NativeThreadListDarwin::ProcessWillResume( - NativeProcessDarwin &process, const ResumeActionList &thread_actions) { - std::lock_guard locker(m_threads_mutex); - - // Update our thread list, because sometimes libdispatch or the kernel will - // spawn threads while a task is suspended. - NativeThreadListDarwin::collection new_threads; - -// TODO implement this. -#if 0 - // First figure out if we were planning on running only one thread, and if - // so, force that thread to resume. - bool run_one_thread; - thread_t solo_thread = THREAD_NULL; - if ((thread_actions.GetSize() > 0) && - (thread_actions.NumActionsWithState(eStateStepping) + - thread_actions.NumActionsWithState (eStateRunning) == 1)) - { - run_one_thread = true; - const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); - size_t num_actions = thread_actions.GetSize(); - for (size_t i = 0; i < num_actions; i++, action_ptr++) - { - if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning) - { - solo_thread = action_ptr->tid; - break; - } - } - } - else - run_one_thread = false; -#endif - - UpdateThreadList(process, true, &new_threads); - -#if 0 - DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; - // If we are planning to run only one thread, any new threads should be - // suspended. - if (run_one_thread) - resume_new_threads.state = eStateSuspended; - - const size_t num_new_threads = new_threads.size(); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - MachThread *thread = m_threads[idx].get(); - bool handled = false; - for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) - { - if (thread == new_threads[new_idx].get()) - { - thread->ThreadWillResume(&resume_new_threads); - handled = true; - break; - } - } - - if (!handled) - { - const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); - // There must always be a thread action for every thread. - assert (thread_action); - bool others_stopped = false; - if (solo_thread == thread->ThreadID()) - others_stopped = true; - thread->ThreadWillResume (thread_action, others_stopped); - } - } - - if (new_threads.size()) - { - for (uint32_t idx = 0; idx < num_new_threads; ++idx) - { - DNBLogThreadedIf (LOG_THREAD, "NativeThreadListDarwin::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)", - process->ProcessID(), - process->StopCount(), - new_threads[idx]->ThreadID(), - new_threads[idx]->IsUserReady()); - } - } -#endif -} - -uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { - std::lock_guard locker(m_threads_mutex); - - // Update our thread list. - UpdateThreadList(process, true); - - for (auto thread_sp : m_threads) { - if (thread_sp) - thread_sp->ThreadDidStop(); - } - return (uint32_t)m_threads.size(); -} - -// Check each thread in our thread list to see if we should notify our client -// of the current halt in execution. -// -// Breakpoints can have callback functions associated with them than can return -// true to stop, or false to continue executing the inferior. -// -// RETURNS -// true if we should stop and notify our clients -// false if we should resume our child process and skip notification -bool NativeThreadListDarwin::ShouldStop(bool &step_more) { - std::lock_guard locker(m_threads_mutex); - for (auto thread_sp : m_threads) { - if (thread_sp && thread_sp->ShouldStop(step_more)) - return true; - } - return false; -} - -// Implement. -#if 0 - -void -NativeThreadListDarwin::NotifyBreakpointChanged (const DNBBreakpoint *bp) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->NotifyBreakpointChanged(bp); - } -} - - -uint32_t -NativeThreadListDarwin::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->EnableHardwareBreakpoint(bp); - } - return INVALID_NUB_HW_INDEX; -} - -bool -NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->DisableHardwareBreakpoint(bp); - } - return false; -} - -// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> -// MachProcess::EnableWatchpoint() -> -// NativeThreadListDarwin::EnableHardwareWatchpoint(). -uint32_t -NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - uint32_t hw_index = INVALID_NUB_HW_INDEX; - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - // On Mac OS X we have to prime the control registers for new threads. - // We do this using the control register data for the first thread, for - // lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) - { - // We know that idx failed for some reason. Let's rollback the - // transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return INVALID_NUB_HW_INDEX; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - } - return hw_index; -} - -bool -NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - - // On Mac OS X we have to prime the control registers for new threads. - // We do this using the control register data for the first thread, for - // lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) - { - // We know that idx failed for some reason. Let's rollback the - // transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return false; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - return true; - } - return false; -} - -uint32_t -NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - // Use an arbitrary thread to retrieve the number of supported hardware - // watchpoints. - if (num_threads) - return m_threads[0]->NumSupportedHardwareWatchpoints(); - return 0; -} - -uint32_t -NativeThreadListDarwin::GetThreadIndexForThreadStoppedWithSignal (const int signo) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - uint32_t should_stop = false; - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().SoftSignal () == signo) - return idx; - } - return UINT32_MAX; -} - -#endif diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h deleted file mode 100644 index 9ab0a7c..0000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h +++ /dev/null @@ -1,138 +0,0 @@ -//===-- NativeThreadListDarwin.h --------------------------------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/19/07. -// -//===----------------------------------------------------------------------===// - -#ifndef __NativeThreadListDarwin_h__ -#define __NativeThreadListDarwin_h__ - -#include -#include -#include - -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-types.h" - -#include "MachException.h" - -// #include "ThreadInfo.h" - -namespace lldb_private { -namespace process_darwin { - -class NativeBreakpointDarwin; -class NativeProcessDarwin; - -class NativeThreadDarwin; -using NativeThreadDarwinSP = std::shared_ptr; - -class NativeThreadListDarwin { -public: - NativeThreadListDarwin(); - ~NativeThreadListDarwin(); - - void Clear(); - - void Dump(Stream &stream) const; - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const; - bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value) const; - nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len); - nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len); - uint32_t SaveRegisterState (nub_thread_t tid); - bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); -#endif - - const char *GetThreadInfo(lldb::tid_t tid) const; - - void ProcessWillResume(NativeProcessDarwin &process, - const ResumeActionList &thread_actions); - - uint32_t ProcessDidStop(NativeProcessDarwin &process); - - bool NotifyException(MachException::Data &exc); - - bool ShouldStop(bool &step_more); - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - const char * GetName (nub_thread_t tid); - nub_state_t GetState (nub_thread_t tid); - nub_thread_t SetCurrentThread (nub_thread_t tid); -#endif - -// TODO: figure out if we need to add this to NativeThreadDarwin yet. -#if 0 - 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); -#endif - -// These methods will be accessed directly from NativeThreadDarwin -#if 0 - 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); -#endif - - size_t GetNumberOfThreads() const; - - lldb::tid_t ThreadIDAtIndex(size_t idx) const; - - lldb::tid_t GetCurrentThreadID(); - - NativeThreadDarwinSP GetCurrentThread(); - - void NotifyBreakpointChanged(const NativeBreakpointDarwin *bp); - - uint32_t EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - - bool DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - - uint32_t EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - - bool DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - - uint32_t GetNumberOfSupportedHardwareWatchpoints() const; - - size_t GetThreadIndexForThreadStoppedWithSignal(const int signo) const; - - NativeThreadDarwinSP GetThreadByID(lldb::tid_t tid) const; - - NativeThreadDarwinSP - GetThreadByMachPortNumber(::thread_t mach_port_number) const; - - lldb::tid_t GetThreadIDByMachPortNumber(::thread_t mach_port_number) const; - - thread_t GetMachPortNumberByThreadID(lldb::tid_t globally_unique_id) const; - -protected: - typedef std::vector collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - // Consider having this return an lldb_private::Status. - uint32_t UpdateThreadList(NativeProcessDarwin &process, bool update, - collection *num_threads = nullptr); - - collection m_threads; - mutable std::recursive_mutex m_threads_mutex; - NativeThreadDarwinSP m_current_thread; - bool m_is_64_bit; -}; - -} // namespace process_darwin -} // namespace lldb_private - -#endif // #ifndef __NativeThreadListDarwin_h__ -- 2.7.4