diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lldb/source/Plugins/Process/Darwin | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'lldb/source/Plugins/Process/Darwin')
16 files changed, 0 insertions, 4900 deletions
diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp b/lldb/source/Plugins/Process/Darwin/CFBundle.cpp deleted file mode 100644 index 3cdd2fa575e7..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- CFBundle.cpp --------------------------------------------*- 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. -// -//===----------------------------------------------------------------------===// - -#include "CFBundle.h" -#include "CFString.h" - -// CFBundle constructor -CFBundle::CFBundle(const char *path) - : CFReleaser<CFBundleRef>(), m_bundle_url() { - if (path && path[0]) - SetPath(path); -} - -// CFBundle copy constructor -CFBundle::CFBundle(const CFBundle &rhs) - : CFReleaser<CFBundleRef>(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<CFBundleRef> - 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 f49dc30f1f8f..000000000000 --- 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<CFBundleRef> { -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<CFURLRef> 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 4dcc05c86657..000000000000 --- a/lldb/source/Plugins/Process/Darwin/CFString.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===-- CFString.cpp --------------------------------------------*- 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. -// -//===----------------------------------------------------------------------===// - -#include "CFString.h" -#include <glob.h> -#include <string> - -// CFString constructor -CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {} - -// CFString copy constructor -CFString::CFString(const CFString &rhs) : CFReleaser<CFStringRef>(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<CFStringRef>() { - 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 d1bd5682689e..000000000000 --- 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 <iosfwd> - -class CFString : public CFReleaser<CFStringRef> { -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 b567524ce63a..000000000000 --- 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 <CoreFoundation/CoreFoundation.h> - -#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 T> class CFReleaser { -public: - // Type names for the avlue - 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<T> ©) { - 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 f70ef97a2bc5..000000000000 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ /dev/null @@ -1,638 +0,0 @@ -//===-- DarwinProcessLauncher.cpp -------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -// -// DarwinProcessLauncher.cpp -// lldb -// -// Created by Todd Fiala on 8/30/16. -// -// - -#include "DarwinProcessLauncher.h" - -// C includes -#include <spawn.h> -#include <sys/ptrace.h> -#include <sys/stat.h> -#include <sys/sysctl.h> - -#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<u_int>(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<CFURLRef> 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<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> 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<posix_spawn_file_actions_t, - int (*)(posix_spawn_file_actions_t *)> - 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<lldb::pid_t>(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<lldb::pid_t>(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 0e65b56a143e..000000000000 --- 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 <mach/machine.h> -#include <sys/types.h> - -// C++ headers -#include <functional> - -// 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 cfd76d1b9c3c..000000000000 --- 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 073ad64b300c..000000000000 --- a/lldb/source/Plugins/Process/Darwin/MachException.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===-- MachException.cpp ---------------------------------------*- 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. -// -//===----------------------------------------------------------------------===// - -#include "MachException.h" - -// C includes -#include <errno.h> -#include <sys/ptrace.h> -#include <sys/types.h> - -// C++ includes -#include <mutex> - -// 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 18e49173b020..000000000000 --- 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 <mach/mach.h> -#include <vector> - -#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<mach_exception_data_type_t> 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<int>(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<Message> 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<mach_exception_data_type_t> exc_data_mask; // Mask to apply to - // exception data, or - // empty to ignore - // exc_data value for - // exception - std::vector<mach_exception_data_type_t> 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 18dbdda9a33b..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ /dev/null @@ -1,1535 +0,0 @@ -//===-- NativeProcessDarwin.cpp ---------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - -#include "NativeProcessDarwin.h" - -// C includes -#include <mach/mach_init.h> -#include <mach/mach_traps.h> -#include <sys/ptrace.h> -#include <sys/stat.h> -#include <sys/sysctl.h> -#include <sys/types.h> - -// 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<NativeProcessDarwin> 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<NativeProcessDarwin> 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<std::recursive_mutex> 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<NativeProcessDarwin *>(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<SBSWatchdogAssertionRef> 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<BKSWatchdogAssertionRef> 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<u_int>(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<std::recursive_mutex> 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<NativeProcessDarwin *>(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<std::recursive_mutex> 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<std::recursive_mutex> 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 6741d4ddc5d8..000000000000 --- 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 <mach/mach_types.h> - -// C++ includes -#include <mutex> -#include <unordered_set> - -#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 bcd6d8c2c4c1..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp +++ /dev/null @@ -1,281 +0,0 @@ -//===-- NativeThreadDarwin.cpp -------------------------------- -*- 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 -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadDarwin.h" - -// C includes -#include <libproc.h> - -// 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 = "<unavailable>"; - 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<NativeProcessDarwin>(GetProcess()); -} diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h deleted file mode 100644 index 616a9a7b9bf0..000000000000 --- 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 <mach/mach_types.h> -#include <sched.h> -#include <sys/proc_info.h> - -// C++ includes -#include <map> -#include <memory> -#include <string> - -// 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<NativeProcessDarwin>; - -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<lldb::addr_t, uint32_t>; - WatchpointIndexMap m_watchpoint_index_map; - // cpu_set_t m_original_cpu_set; // For single-step workaround. -#endif -}; - -typedef std::shared_ptr<NativeThreadDarwin> 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 1faa5b219cbc..000000000000 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp +++ /dev/null @@ -1,702 +0,0 @@ -//===-- NativeThreadListDarwin.cpp ------------------------------------*- 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. -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadListDarwin.h" - -// C includes -#include <inttypes.h> -#include <mach/vm_map.h> -#include <sys/sysctl.h> - -// 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> locker(m_threads_mutex); - return static_cast<size_t>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<uint32_t>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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 9ab0a7c8c802..000000000000 --- 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 <memory> -#include <mutex> -#include <vector> - -#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<NativeThreadDarwin>; - -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<NativeThreadDarwinSP> 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__ |