diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Darwin')
16 files changed, 3230 insertions, 4047 deletions
diff --git a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp b/lldb/source/Plugins/Process/Darwin/CFBundle.cpp index fdcb7cc2fcb..7b080e60cdb 100644 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.cpp +++ b/lldb/source/Plugins/Process/Darwin/CFBundle.cpp @@ -17,81 +17,63 @@ //---------------------------------------------------------------------- // CFBundle constructor //---------------------------------------------------------------------- -CFBundle::CFBundle(const char *path) : - CFReleaser<CFBundleRef>(), - m_bundle_url() -{ - if (path && path[0]) - SetPath(path); +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::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; +CFBundle &CFBundle::operator=(const CFBundle &rhs) { + *this = rhs; + return *this; } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -CFBundle::~CFBundle() -{ -} +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())); - } +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; + } + return get() != NULL; } -CFStringRef -CFBundle::GetIdentifier () const -{ - CFBundleRef bundle = get(); - if (bundle != NULL) - return ::CFBundleGetIdentifier (bundle); - return 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; +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 index e08290add73..09957af534b 100644 --- a/lldb/source/Plugins/Process/Darwin/CFBundle.h +++ b/lldb/source/Plugins/Process/Darwin/CFBundle.h @@ -16,28 +16,23 @@ #include "CFUtils.h" -class CFBundle : public CFReleaser<CFBundleRef> -{ +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); + //------------------------------------------------------------------ + // 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; + CFStringRef GetIdentifier() const; + + CFURLRef CopyExecutableURL() const; - CFURLRef - CopyExecutableURL () const; - protected: - CFReleaser<CFURLRef> m_bundle_url; + 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 index 819024ca3bc..84ad56774d7 100644 --- a/lldb/source/Plugins/Process/Darwin/CFString.cpp +++ b/lldb/source/Plugins/Process/Darwin/CFString.cpp @@ -12,136 +12,110 @@ //===----------------------------------------------------------------------===// #include "CFString.h" -#include <string> #include <glob.h> +#include <string> //---------------------------------------------------------------------- // CFString constructor //---------------------------------------------------------------------- -CFString::CFString(CFStringRef s) : - CFReleaser<CFStringRef> (s) -{ -} +CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {} //---------------------------------------------------------------------- // CFString copy constructor //---------------------------------------------------------------------- -CFString::CFString(const CFString& rhs) : - CFReleaser<CFStringRef> (rhs) -{ - -} +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::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)); - } +CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding) + : CFReleaser<CFStringRef>() { + if (cstr && cstr[0]) { + reset( + ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); + } } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -CFString::~CFString() -{ -} +CFString::~CFString() {} -const char * -CFString::GetFileSystemRepresentation(std::string& s) -{ - return CFString::FileSystemRepresentation(get(), s); +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::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); - } +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(); + } + 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(); +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); +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(); - } - } +// 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; + } + return NULL; } // Static function that puts a copy of the file system representation of CF_STR @@ -150,52 +124,40 @@ CFString::UTF8 (CFStringRef cf_str, std::string& str) // 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(); - } - } +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; + } + str.erase(); + return NULL; } - -CFIndex -CFString::GetLength() const -{ - CFStringRef str = get(); - if (str) - return CFStringGetLength (str); - return 0; +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(); -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(); + return expanded_path.c_str(); } - diff --git a/lldb/source/Plugins/Process/Darwin/CFString.h b/lldb/source/Plugins/Process/Darwin/CFString.h index 73945a28a65..18d60a5a74b 100644 --- a/lldb/source/Plugins/Process/Darwin/CFString.h +++ b/lldb/source/Plugins/Process/Darwin/CFString.h @@ -17,27 +17,27 @@ #include "CFUtils.h" #include <iosfwd> -class CFString : public CFReleaser<CFStringRef> -{ +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 (); + //------------------------------------------------------------------ + // 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); + 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 index afa984fa11c..a904cd0ea6f 100644 --- a/lldb/source/Plugins/Process/Darwin/CFUtils.h +++ b/lldb/source/Plugins/Process/Darwin/CFUtils.h @@ -23,59 +23,56 @@ // call CFRelease() on any valid pointer it owns unless that pointer is // explicitly released using the release() member function. //---------------------------------------------------------------------- -template <class T> -class CFReleaser -{ +template <class T> class CFReleaser { public: - // Type names for the avlue - typedef T element_type; + // Type names for the avlue + typedef T element_type; - // Constructors and destructors - CFReleaser(T ptr = NULL) : _ptr(ptr) { } - CFReleaser(const CFReleaser& copy) : _ptr(copy.get()) - { - if (get()) - ::CFRetain(get()); - } - virtual ~CFReleaser() { reset(); } + // 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>& copy) - { - 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; } + // 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; } + // 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; - } - } + // 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; + } - // Release ownership without calling CFRelease - T release() { T tmp = _ptr; _ptr = NULL; return tmp; } private: - element_type _ptr; + element_type _ptr; }; -#endif // #ifdef __cplusplus -#endif // #ifndef __CFUtils_h__ - +#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 index 91abe4f26e2..408f0abe72d 100644 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp +++ b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp @@ -15,7 +15,7 @@ #include <sys/sysctl.h> #ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif // LLDB includes @@ -35,703 +35,610 @@ 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 { +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; +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; - } - } - } +static bool ResolveExecutablePath(const char *path, char *resolved_path, + size_t resolved_path_size) { + if (path == NULL || path[0] == '\0') + return false; - 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; + 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; + } } - 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; - } - } + } + + 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; + } + return false; } // TODO check if we have a general purpose fork and exec. We may be // able to get rid of this entirely. -static Error -ForkChildForPTraceDebugging(const char *path, - char const *argv[], - char const *envp[], - ::pid_t *pid, - int *pty_fd) -{ - Error 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. - lldb_utility::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) - { - //-------------------------------------------------------------- - // Error 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(); - } - } +static Error ForkChildForPTraceDebugging(const char *path, char const *argv[], + char const *envp[], ::pid_t *pid, + int *pty_fd) { + Error 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. + lldb_utility::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) { + //-------------------------------------------------------------- + // Error 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 + //-------------------------------------------------------------- -static Error -CreatePosixSpawnFileAction(const FileAction &action, - posix_spawn_file_actions_t *file_actions) -{ - Error error; + // Debug this process. + ::ptrace(PT_TRACE_ME, 0, 0, 0); - // 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()); - } + // Get BSD signals as mach exceptions. + ::ptrace(PT_SIGEXC, 0, 0, 0); - // Validate args. - if (!file_actions) - { - error.SetErrorString("mandatory file_actions arg is null"); - return error; - } + // 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. - // 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; - } + // Set the child process group to match its pid. + ::setpgid(0, 0); - 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; - } + // Sleep a bit to before the exec call. + ::sleep(1); - case FileAction::eFileActionNone: - default: - if (log) - log->Printf("%s(): unsupported file action %u", - __FUNCTION__, action.GetAction()); - break; + // Turn this process into the given executable. + ::execv(path, (char *const *)argv); } - - return error; + // 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 Error -PosixSpawnChildForPTraceDebugging(const char *path, - ProcessLaunchInfo &launch_info, - ::pid_t *pid, - cpu_type_t *actual_cpu_type) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!pid) - { - error.SetErrorStringWithFormat("%s(): pid arg cannot be null", - __FUNCTION__); - return error; +CreatePosixSpawnFileAction(const FileAction &action, + posix_spawn_file_actions_t *file_actions) { + Error 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; } - - 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()); + 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; } - - int error_code; - if ((error_code = ::posix_spawnattr_init(&attr)) != 0) - { - if (log) - log->Printf("::posix_spawnattr_init(&attr) failed"); - 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; + } - // 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) - { - if (log) - log->Printf("::posix_spawnattr_setflags(&attr, " - "POSIX_SPAWN_START_SUSPENDED%s) failed: %s", - flags & _POSIX_SPAWN_DISABLE_ASLR ? - " | _POSIX_SPAWN_DISABLE_ASLR" : "", - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } + case FileAction::eFileActionNone: + default: + if (log) + log->Printf("%s(): unsupported file action %u", __FUNCTION__, + action.GetAction()); + break; + } -#if !defined(__arm__) + return error; +} - // 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) - { - if (log) - log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, " - "cpu_type = 0x%8.8x, count => %llu): %s", - desired_cpu_type, (uint64_t)ocount, - 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 +static Error PosixSpawnChildForPTraceDebugging(const char *path, + ProcessLaunchInfo &launch_info, + ::pid_t *pid, + cpu_type_t *actual_cpu_type) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - posix_spawn_file_actions_t file_actions; - if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) - { - if (log) - log->Printf("::posix_spawn_file_actions_init(&file_actions) " - "failed: %s", - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; - } + 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) { + if (log) + log->Printf("::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) { + if (log) + log->Printf("::posix_spawnattr_setflags(&attr, " + "POSIX_SPAWN_START_SUSPENDED%s) failed: %s", + flags & _POSIX_SPAWN_DISABLE_ASLR + ? " | _POSIX_SPAWN_DISABLE_ASLR" + : "", + 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()) - { - if (log) - log->Printf("%s(): error converting FileAction to posix_spawn " - "file action: %s", __FUNCTION__, error.AsCString()); - return error; - } - } +#if !defined(__arm__) - // 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) - { - if (log) - log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions " - "= %p, attr = %p, argv = %p, envp = %p) failed: %s", - pid, path, &file_actions, &attr, argv, envp, - strerror(error_code)); - error.SetError(error_code, eErrorTypePOSIX); - return error; + // 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) { + if (log) + log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, " + "cpu_type = 0x%8.8x, count => %llu): %s", + desired_cpu_type, (uint64_t)ocount, 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 (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 - if (actual_cpu_type) - { - *actual_cpu_type = GetCPUTypeForLocalProcess(*pid); - if (log) - log->Printf("%s(): cpu type for launched process pid=%i: " - "cpu_type=0x%8.8x", __FUNCTION__, *pid, - *actual_cpu_type); + posix_spawn_file_actions_t file_actions; + if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) { + if (log) + log->Printf("::posix_spawn_file_actions_init(&file_actions) " + "failed: %s", + 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()) { + if (log) + log->Printf("%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) { + if (log) + log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions " + "= %p, attr = %p, argv = %p, envp = %p) failed: %s", + pid, path, &file_actions, &attr, argv, envp, + strerror(error_code)); + error.SetError(error_code, eErrorTypePOSIX); return error; -} + } -Error -LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - LaunchFlavor *launch_flavor) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (!launch_flavor) - { - error.SetErrorString("mandatory launch_flavor field was null"); - 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); 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()); - } + log->Printf("%s(): cpu type for launched process pid=%i: " + "cpu_type=0x%8.8x", + __FUNCTION__, *pid, *actual_cpu_type); + } + + return error; +} - // 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; +Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, + LaunchFlavor *launch_flavor) { + Error 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; - } + // 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; - } + // 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 + // 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'; - // Attempt to resolve the binary name to an absolute path. - char resolved_path[PATH_MAX]; - resolved_path[0] = '\0'; + if (log) + log->Printf("%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))) { if (log) - log->Printf("%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)) ) - { - if (log) - log->Printf("%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 - { - if (log) - log->Printf("%s(): resolved given binary path to: \"%s\"", - __FUNCTION__, resolved_path); - } + log->Printf("%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 { + if (log) + log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__, + resolved_path); + } + + char launch_err_str[PATH_MAX]; + launch_err_str[0] = '\0'; - 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; + // 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; } - - // 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; + } 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; + 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; + 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; + 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; } - - 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__); + 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 - // We're done with the launch side of the operation. + 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 - +} +} // namespaces diff --git a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h index d06056afbb6..d1af4d09f8b 100644 --- a/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h +++ b/lldb/source/Plugins/Process/Darwin/DarwinProcessLauncher.h @@ -23,10 +23,8 @@ #include "LaunchFlavor.h" -namespace lldb_private -{ -namespace darwin_process_launcher -{ +namespace lldb_private { +namespace darwin_process_launcher { // ============================================================================= /// Launches a process for debugging. /// @@ -41,9 +39,8 @@ namespace darwin_process_launcher /// @param[out] launch_flavor /// Contains the launch flavor used when launching the process. // ============================================================================= -Error -LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, - lldb_private::process_darwin::LaunchFlavor *launch_flavor); +Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, + lldb_private::process_darwin::LaunchFlavor *launch_flavor); } // darwin_process_launcher } // lldb_private diff --git a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h b/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h index 02182f7528a..7b161712cff 100644 --- a/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h +++ b/lldb/source/Plugins/Process/Darwin/LaunchFlavor.h @@ -13,22 +13,21 @@ namespace lldb_private { namespace process_darwin { -enum class LaunchFlavor -{ - Default = 0, - PosixSpawn = 1, - ForkExec = 2, +enum class LaunchFlavor { + Default = 0, + PosixSpawn = 1, + ForkExec = 2, #ifdef WITH_SPRINGBOARD - SpringBoard = 3, + SpringBoard = 3, #endif #ifdef WITH_BKS - BKS = 4, + BKS = 4, #endif #ifdef WITH_FBS - FBS = 5 + FBS = 5 #endif }; - -}} // namespaces +} +} // namespaces #endif /* LaunchFlavor_h */ diff --git a/lldb/source/Plugins/Process/Darwin/MachException.cpp b/lldb/source/Plugins/Process/Darwin/MachException.cpp index d9693195e38..81706441494 100644 --- a/lldb/source/Plugins/Process/Darwin/MachException.cpp +++ b/lldb/source/Plugins/Process/Darwin/MachException.cpp @@ -15,8 +15,8 @@ // C includes #include <errno.h> -#include <sys/types.h> #include <sys/ptrace.h> +#include <sys/types.h> // C++ includes #include <mutex> @@ -33,51 +33,29 @@ 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 -); +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); +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); // Any access to the g_message variable should be done by locking the // g_message_mutex first, using the g_message variable, then unlocking @@ -86,107 +64,71 @@ extern "C" boolean_t mach_exc_server( 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) - { - log->Printf("::%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( + 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) { + log->Printf("::%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) - { - log->Printf("::%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)); - } - mach_port_deallocate (mach_task_self(), task_port); - mach_port_deallocate (mach_task_self(), thread_port); - - 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) { + log->Printf("::%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)); + } + mach_port_deallocate(mach_task_self(), task_port); + mach_port_deallocate(mach_task_self(), thread_port); + + 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) - { - log->Printf("::%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; +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) { + log->Printf("::%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; } #if 0 @@ -216,316 +158,249 @@ MachException::Message::Dump(Stream &stream) const } #endif -bool -MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info, - const UnixSignals &signals, - Stream &stream) const -{ - if (!stop_info) - return false; +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)); + // 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) - ? '}' : ',')); - } + 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]; + // 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; + return true; } -Error -MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port) -{ - Error 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 - log->Printf("::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); +Error MachException::Message::Receive(mach_port_t port, + mach_msg_option_t options, + mach_msg_timeout_t timeout, + mach_port_t notify_port) { + Error 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 + log->Printf("::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) { + log->Printf("::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; +} - // Dump any errors we get - if (error.Fail() && log) - { - log->Printf("::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); } -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; + // locker will keep a mutex locked until it goes out of scope + // PThreadMutex::Locker locker(&g_message_mutex); + // DNBLogThreaded("calling mach_exc_server"); + 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)); + if (log) + log->Printf("MachException::Message::%s(): mach_exc_server " + "returned zero...", + __FUNCTION__); + } + g_message = NULL; + return success; } -bool -MachException::Message::CatchExceptionRaise(task_t task) -{ - bool success = false; - // locker will keep a mutex locked until it goes out of scope -// PThreadMutex::Locker locker(&g_message_mutex); - // DNBLogThreaded("calling mach_exc_server"); - 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)); +Error MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, + int signal) { + // Reply to the exception... + Error 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); if (log) - log->Printf("MachException::Message::%s(): mach_exc_server " - "returned zero...", __FUNCTION__); + log->Printf("MachException::Message::%s(): pid_for_task() " + "failed: %s", + __FUNCTION__, error.AsCString()); + return error; + } } - g_message = NULL; - return success; -} -Error -MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, - int signal) -{ - // Reply to the exception... - Error 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); - if (log) - log->Printf("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); - 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()) - { - if (log) - log->Printf("::ptrace(request = PT_THUPDATE, pid = " - "0x%4.4x, tid = 0x%4.4x, signal = %i)", - state_pid, state.thread_port, soft_signal); - return error; - } - } + if (!error.Success()) { + if (log) + log->Printf("::ptrace(request = PT_THUPDATE, pid = " + "0x%4.4x, tid = 0x%4.4x, signal = %i)", + state_pid, state.thread_port, soft_signal); + return error; + } } + } + + if (log) + log->Printf("::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); - if (log) - log->Printf("::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) - { - log->Printf("mach_msg(): returned an error when replying " - "to a mach exception: error = %u (%s)", - error.GetError(), error.AsCString()); - } - else - { - log->Printf("::mach_msg() - failed (child of task): %u (%s)", - error.GetError(), error.AsCString()); - } + // 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) { + log->Printf("mach_msg(): returned an error when replying " + "to a mach exception: error = %u (%s)", + error.GetError(), error.AsCString()); + } else { + log->Printf("::mach_msg() - failed (child of task): %u (%s)", + error.GetError(), error.AsCString()); } + } - return error; + 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) +#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. +// Don't listen for EXC_RESOURCE, it should really get handled by the system +// handler. #ifndef EXC_RESOURCE #define EXC_RESOURCE 11 @@ -537,148 +412,132 @@ MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, #define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) -Error -MachException::PortInfo::Save(task_t task) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_VERBOSE)); +Error MachException::PortInfo::Save(task_t task) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) - log->Printf("MachException::PortInfo::%s(task = 0x%4.4x)", - __FUNCTION__, task); + if (log) + log->Printf("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; + // 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); + 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()) - { - log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask = " - "0x%x, maskCnt => %u, ports, behaviors, flavors)", - task, mask, count); - } - else - { - log->Printf("::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 (log) { + if (error.Success()) { + log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask = " + "0x%x, maskCnt => %u, ports, behaviors, flavors)", + task, mask, count); + } else { + log->Printf("::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()) - { - log->Printf("::task_get_exception_ports(task = 0x%4.4x, " - "mask = 0x%x, maskCnt => %u, ports, behaviors, " - "flavors)", task, mask, count); - } - else - { - log->Printf("::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; + 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()) { + log->Printf("::task_get_exception_ports(task = 0x%4.4x, " + "mask = 0x%x, maskCnt => %u, ports, behaviors, " + "flavors)", + task, mask, count); + } else { + log->Printf("::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()); + } } - return error; + } + if (error.Fail()) { + mask = 0; + count = 0; + } + return error; } -Error -MachException::PortInfo::Restore(task_t task) -{ - Error error; +Error MachException::PortInfo::Restore(task_t task) { + Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_VERBOSE)); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) - log->Printf("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()) - { - log->Printf("::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 - { - log->Printf("::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; + if (log) + log->Printf("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()) { + log->Printf("::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 { + log->Printf("::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; + 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"; +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"; + case EXC_CRASH: + return "EXC_CRASH"; #endif - default: - break; - } - return NULL; + default: + break; + } + return NULL; } diff --git a/lldb/source/Plugins/Process/Darwin/MachException.h b/lldb/source/Plugins/Process/Darwin/MachException.h index a96090b3bd8..ac8cd7030c5 100644 --- a/lldb/source/Plugins/Process/Darwin/MachException.h +++ b/lldb/source/Plugins/Process/Darwin/MachException.h @@ -11,150 +11,127 @@ // //===----------------------------------------------------------------------===// - #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" -#include "lldb/Host/Debug.h" -namespace lldb_private -{ -namespace process_darwin -{ +namespace lldb_private { +namespace process_darwin { -typedef union MachMessageTag -{ - mach_msg_header_t hdr; - char data[1024]; +typedef union MachMessageTag { + mach_msg_header_t hdr; + char data[1024]; } MachMessage; - -class MachException -{ +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; - - Error - Save(task_t task); - - Error - 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); - - Error - Reply(::pid_t inferior_pid, task_t inferior_task, int signal); - - Error - 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); + 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; + + Error Save(task_t task); + + Error 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); + + Error Reply(::pid_t inferior_pid, task_t inferior_task, int signal); + + Error 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 diff --git a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp index d0eaac3c793..e56375ebaa4 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp @@ -40,170 +40,142 @@ 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; - }; +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 // ----------------------------------------------------------------------------- -Error -NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info, - NativeProcessProtocol::NativeDelegate - &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - Error error; - - // Verify the working directory is valid if one was specified. - FileSpec working_dir(launch_info.GetWorkingDirectory()); - if (working_dir && - (!working_dir.ResolvePath() || - working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) - { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return error; - } +Error NativeProcessProtocol::Launch( + ProcessLaunchInfo &launch_info, + NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, + NativeProcessProtocolSP &native_process_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + Error error; + + // Verify the working directory is valid if one was specified. + FileSpec working_dir(launch_info.GetWorkingDirectory()); + if (working_dir && + (!working_dir.ResolvePath() || + working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) { + 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; + // Launch the inferior. + int pty_master_fd = -1; + LaunchFlavor launch_flavor = LaunchFlavor::Default; - error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor); + error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor); - // Handle launch failure. - if (!error.Success()) - { - if (log) - log->Printf("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) - { - if (log) - log->Printf("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()) - { - if (log) - log->Printf("NativeProcessDarwin::%s() aborting, failed to finalize" - " the launching of the process: %s", - __FUNCTION__, error.AsCString()); - return error; - } + // Handle launch failure. + if (!error.Success()) { + if (log) + log->Printf("NativeProcessDarwin::%s() failed to launch 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; + // Handle failure to return a pid. + if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { + if (log) + log->Printf("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; + } -Error -NativeProcessProtocol::Attach(lldb::pid_t pid, - NativeProcessProtocol::NativeDelegate - &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &native_process_sp) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Finalize the processing needed to debug the launched process with + // a NativeProcessDarwin instance. + error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop); + if (!error.Success()) { if (log) - log->Printf ("NativeProcessDarwin::%s(pid = %" PRIi64 ")", __FUNCTION__, - pid); + log->Printf("NativeProcessDarwin::%s() aborting, failed to finalize" + " the launching of the process: %s", + __FUNCTION__, error.AsCString()); + return error; + } - // Retrieve the architecture for the running process. - ArchSpec process_arch; - Error error = ResolveProcessArchitecture(pid, process_arch); - if (!error.Success()) - return error; + // Return the process and process id to the caller through the launch args. + native_process_sp = np_darwin_sp; + 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)); +Error NativeProcessProtocol::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("NativeProcessDarwin::%s(pid = %" PRIi64 ")", __FUNCTION__, + pid); + + // Retrieve the architecture for the running process. + ArchSpec process_arch; + Error error = ResolveProcessArchitecture(pid, process_arch); + if (!error.Success()) + return error; - if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) - { - error.SetErrorStringWithFormat("failed to register the native " - "delegate"); - 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)); - native_process_darwin_sp->AttachToInferior(mainloop, pid, error); - if (!error.Success()) - return error; + if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) { + error.SetErrorStringWithFormat("failed to register the native " + "delegate"); + return error; + } - native_process_sp = native_process_darwin_sp; + 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(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() -{ -} +NativeProcessDarwin::~NativeProcessDarwin() {} // ----------------------------------------------------------------------------- // Instance methods // ----------------------------------------------------------------------------- -Error -NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, - MainLoop &main_loop) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); +Error NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, + MainLoop &main_loop) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); #if 0 m_path = path; @@ -213,772 +185,680 @@ NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, m_args.push_back(arg); #endif - error = StartExceptionThread(); - if (!error.Success()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): failure starting the " - "mach exception port monitor thread: %s", - __FUNCTION__, error.AsCString()); + error = StartExceptionThread(); + if (!error.Success()) { + if (log) + log->Printf("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); + // 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; + 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; + if (log) + log->Printf("NativeProcessDarwin::%s(): successfully spawned " + "process with pid %" PRIu64, + __FUNCTION__, m_pid); + } else { + error.SetErrorToErrno(); + SetState(eStateExited); + if (log) + log->Printf("NativeProcessDarwin::%s(): error: failed to " + "attach to spawned pid %" PRIu64 " (error=%d (%s))", + __FUNCTION__, m_pid, (int)error.GetError(), + error.AsCString()); + 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; - if (log) - log->Printf("NativeProcessDarwin::%s(): successfully spawned " - "process with pid %" PRIu64, __FUNCTION__, m_pid); - } - else - { - error.SetErrorToErrno(); - SetState(eStateExited); - if (log) - log->Printf("NativeProcessDarwin::%s(): error: failed to " - "attach to spawned pid %" PRIu64 " (error=%d (%s))", - __FUNCTION__, m_pid, (int)error.GetError(), - error.AsCString()); - return error; - } - } + if (log) + log->Printf("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()) { if (log) - log->Printf("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()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): failed to start waitpid() " - "thread: %s", __FUNCTION__, error.AsCString()); - kill(SIGKILL, static_cast<::pid_t>(m_pid)); - return error; - } + log->Printf("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. - if (log) - log->Printf("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; - } + 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. + if (log) + log->Printf("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); + // Indicate that we're stopped, as we always launch suspended. + SetState(eStateStopped); - // Success. - return error; + // Success. + return error; } -Error -NativeProcessDarwin::SaveExceptionPortInfo() -{ - return m_exc_port_info.Save(m_task); +Error 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::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; +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); - - if (log) - log->Printf("NativeProcessDarwin::%s(): new queued message count: %lu", - __FUNCTION__, m_exception_messages.size()); +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); + + if (log) + log->Printf("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) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): cannot run mach exception " - "thread, mandatory process arg was null", __FUNCTION__); - return nullptr; - } +void *NativeProcessDarwin::ExceptionThread(void *arg) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + if (!arg) { + if (log) + log->Printf("NativeProcessDarwin::%s(): cannot run mach exception " + "thread, mandatory process arg was null", + __FUNCTION__); + return nullptr; + } - return reinterpret_cast<NativeProcessDarwin*>(arg)->DoExceptionThread(); + return reinterpret_cast<NativeProcessDarwin *>(arg)->DoExceptionThread(); } -void* -NativeProcessDarwin::DoExceptionThread() -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_VERBOSE)); - +void *NativeProcessDarwin::DoExceptionThread() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + + if (log) + log->Printf("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; + Error 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)); if (log) - log->Printf("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; - Error 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)); - if (log) - log->Printf("::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) " - "=> %p", pid, watchdog.get()); - - if (watchdog.get()) - { - ::SBSWatchdogAssertionRenew (watchdog.get()); - - CFTimeInterval watchdogRenewalInterval = - ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get()); - if (log) - log->Printf("::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; - } - } + log->Printf("::SBSWatchdogAssertionCreateForPID(NULL, %4.4x, 60) " + "=> %p", + pid, watchdog.get()); + + if (watchdog.get()) { + ::SBSWatchdogAssertionRenew(watchdog.get()); + + CFTimeInterval watchdogRenewalInterval = + ::SBSWatchdogAssertionGetRenewalInterval(watchdog.get()); + if (log) + log->Printf("::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) + 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)); - } + 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); + // 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()) { + if (log) + log->Printf("NativeProcessDarwin::%s(): the inferior " + "exception port is no longer valid, " + "canceling exception thread...", + __FUNCTION__); + // Should we be setting a process state here? + break; } - 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); + + // Make sure the inferior task is still valid. + if (IsTaskValid()) { + // Task is still ok. + if (log) + log->Printf("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. + if (log) + log->Printf("NativeProcessDarwin::%s(): the inferior task " + "has exited, and so will we...", + __FUNCTION__); + // Does this race at all with our waitpid()? + SetState(eStateExited); + break; } - 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); + } 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. + if (log) + log->Printf("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. + if (log) + log->Printf("NativeProcessDarwin::%s(): the inferior " + "task has exited, and so will we...", + __FUNCTION__); + // Does this race at all with our waitpid()? + SetState(eStateExited); + break; + } } - if (error.Success()) - { - // We successfully received an exception. - if (exception_message.CatchExceptionRaise(task)) - { - ++num_exceptions_received; - ExceptionMessageReceived(exception_message); - } +#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) + if (watchdog.get()) { + watchdog_elapsed += periodic_timeout; + if (watchdog_elapsed >= watchdog_timeout) { + if (log) + log->Printf("SBSWatchdogAssertionRenew(%p)", watchdog.get()); + ::SBSWatchdogAssertionRenew(watchdog.get()); + watchdog_elapsed = 0; + } } - 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()) - { - if (log) - log->Printf("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. - if (log) - log->Printf("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. - if (log) - log->Printf("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. - if (log) - log->Printf("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. - if (log) - log->Printf("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) - { - if (log) - log->Printf("SBSWatchdogAssertionRenew(%p)", - watchdog.get()); - ::SBSWatchdogAssertionRenew (watchdog.get()); - watchdog_elapsed = 0; - } - } #endif - } - else - { - if (log) - log->Printf("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()); + } else { + if (log) + log->Printf("NativeProcessDarwin::%s(): continuing after " + "receiving an unexpected error: %u (%s)", + __FUNCTION__, error.GetError(), error.AsCString()); + // TODO: notify of error? + } } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - - if (log) - log->Printf("NativeProcessDarwin::%s(%p): thread exiting...", - __FUNCTION__, this); - return nullptr; + } + +#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) + + if (log) + log->Printf("NativeProcessDarwin::%s(%p): thread exiting...", __FUNCTION__, + this); + return nullptr; } -Error -NativeProcessDarwin::StartExceptionThread() -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__); - - // Make sure we've looked up the inferior port. - TaskPortForProcessID(error); +Error NativeProcessDarwin::StartExceptionThread() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__); - // 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; - } + // Make sure we've looked up the inferior port. + TaskPortForProcessID(error); - // Get the mach port for the process monitor. - mach_port_t task_self = mach_task_self(); + // 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; + } - // 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()) - { - if (log) - log->Printf("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; - } + // Get the mach port for the process monitor. + mach_port_t task_self = mach_task_self(); - // 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()) - { - if (log) - log->Printf("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; - } + // 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()) { + if (log) + log->Printf("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; + } - // Save the original state of the exception ports for our child process. - error = SaveExceptionPortInfo(); - if (error.Fail() || (m_exc_port_info.mask == 0)) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): SaveExceptionPortInfo() " - "failed, cannot install exception handler: %s", - __FUNCTION__, 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()) { + if (log) + log->Printf("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; + } - // 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()) - { - if (log) - log->Printf("::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; - } + // Save the original state of the exception ports for our child process. + error = SaveExceptionPortInfo(); + if (error.Fail() || (m_exc_port_info.mask == 0)) { + if (log) + log->Printf("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()) { + if (log) + log->Printf("::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()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): failed to create Mach " - "exception-handling thread: %u (%s)", __FUNCTION__, - error.GetError(), error.AsCString()); - } + // Create the exception thread. + auto pthread_err = + ::pthread_create(&m_exception_thread, nullptr, ExceptionThread, this); + error.SetError(pthread_err, eErrorTypePOSIX); + if (error.Fail()) { + if (log) + log->Printf("NativeProcessDarwin::%s(): failed to create Mach " + "exception-handling thread: %u (%s)", + __FUNCTION__, error.GetError(), error.AsCString()); + } - return error; + return error; } lldb::addr_t -NativeProcessDarwin::GetDYLDAllImageInfosAddress(Error &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; +NativeProcessDarwin::GetDYLDAllImageInfosAddress(Error &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; - } + 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; + // 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; +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; + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) + return 0; - mib[len] = pid; - len++; + 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; + 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; +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. - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_VERBOSE)); - - std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); - if (log) - log->Printf("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; +task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { + // We have a complete bundle of exceptions for our child process. + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - // 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; - Error 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) - { - if (log) - log->Printf("exec: inferior task port changed " - "from 0x%4.4x to 0x%4.4x", old_task, - new_task); - } - } - } - else - { - if (log) - log->Printf("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) - { - if (log) - log->Printf("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(); + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); + if (log) + log->Printf("NativeProcessDarwin::%s(): processing %lu exception " + "messages.", + __FUNCTION__, m_exception_messages.size()); - // TODO hook up breakpoints. - // m_breakpoints.DisableAll(); - } - - if (m_sent_interrupt_signo != 0) - { - if (received_interrupt) - { - if (log) - log->Printf("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; - if (log) - log->Printf("NativeProcessDarwin::%s(): auto " - "resuming due to unhandled interrupt " - "signal %i", __FUNCTION__, - m_auto_resume_signo); - } - m_auto_resume_signo = 0; - } - } - else - { - if (log) - log->Printf("NativeProcessDarwin::%s(): didn't get signal " - "%i after MachProcess::Interrupt()", - __FUNCTION__, m_sent_interrupt_signo); + 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; + Error 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) { + if (log) + log->Printf("exec: inferior task port changed " + "from 0x%4.4x to 0x%4.4x", + old_task, new_task); } + } + } else { + if (log) + log->Printf("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; + } } - // 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 (m_did_exec) { + cpu_type_t process_cpu_type = GetCPUTypeForLocalProcess(m_pid); + if (m_cpu_type != process_cpu_type) { + if (log) + log->Printf("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) { if (log) - { - StreamString stream; - m_exception_messages[i].Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); + log->Printf("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; + if (log) + log->Printf("NativeProcessDarwin::%s(): auto " + "resuming due to unhandled interrupt " + "signal %i", + __FUNCTION__, m_auto_resume_signo); + } + m_auto_resume_signo = 0; } + } else { + if (log) + log->Printf("NativeProcessDarwin::%s(): didn't get signal " + "%i after MachProcess::Interrupt()", + __FUNCTION__, m_sent_interrupt_signo); + } } - - if (log) - { - StreamString stream; - m_thread_list.Dump(stream); - stream.Flush(); - log->PutCString(stream.GetString().c_str()); + } + + // 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); } - bool step_more = false; - if (m_thread_list.ShouldStop(step_more) && (auto_resume == false)) - { - // TODO - need to hook up event system here. !!!! + 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 @@ -990,836 +870,707 @@ NativeProcessDarwin::ExceptionMessageBundleComplete() m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout); #endif - SetState(eStateStopped); - } - else - { - // Resume without checking our current state. - PrivateResume(); - } + SetState(eStateStopped); + } else { + // Resume without checking our current state. + PrivateResume(); + } - return m_task; + return m_task; } -void -NativeProcessDarwin::StartSTDIOThread() -{ - // TODO implement +void NativeProcessDarwin::StartSTDIOThread() { + // TODO implement } -Error -NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) -{ - Error 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()) - { - if (log) - log->Printf("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 File(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()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): failed to create waitpid " - "handling thread: %u (%s)", __FUNCTION__, - error.GetError(), error.AsCString()); - return error; - } - +Error NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop) { + Error 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()) { + if (log) + log->Printf("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 File(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()) { + if (log) + log->Printf("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) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): cannot run waitpid " - "thread, mandatory process arg was null", __FUNCTION__); - return nullptr; - } +void *NativeProcessDarwin::WaitpidThread(void *arg) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (!arg) { + if (log) + log->Printf("NativeProcessDarwin::%s(): cannot run waitpid " + "thread, mandatory process arg was null", + __FUNCTION__); + return nullptr; + } - return reinterpret_cast<NativeProcessDarwin*>(arg)->DoWaitpidThread(); + 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); - } +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) - { - if (log) - log->Printf("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(); - - Error error; - int status = -1; +void *NativeProcessDarwin::DoWaitpidThread() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - 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. - if (log) - log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" - PRIu64 ", &status, 0) interrupted, continuing", - __FUNCTION__, m_pid); - continue; - } - - // This error is not okay, abort. - if (log) - log->Printf("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. - if (log) - log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ", &status, 0) => %i, status = %i", __FUNCTION__, - m_pid, child_pid, status); - - // Handle the result. - if (WIFSTOPPED(status)) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 - ") received a stop, continuing waitpid() loop", - __FUNCTION__, m_pid); - continue; - } - else // if (WIFEXITED(status) || WIFSIGNALED(status)) - { - if (log) - log->Printf("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. + if (m_pid == LLDB_INVALID_PROCESS_ID) { if (log) - log->Printf("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); + log->Printf("NativeProcessDarwin::%s(): inferior process ID is " + "not set, cannot waitpid on it", + __FUNCTION__); return nullptr; -} + } -Error -NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid, int status) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Name the thread. + pthread_setname_np("waitpid thread"); - size_t bytes_written = 0; + // Ensure we don't get CPU starved. + MaybeRaiseThreadPriority(); - // Send the pid. - error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written); - if (error.Fail() || (bytes_written < sizeof(pid))) - { + Error 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. if (log) - log->Printf("NativeProcessDarwin::%s() - failed to write " - "waitpid exiting pid to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); - return error; + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 + ", &status, 0) interrupted, continuing", + __FUNCTION__, m_pid); + continue; + } + + // This error is not okay, abort. + if (log) + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 + ", &status, 0) aborting due to error: %u (%s)", + __FUNCTION__, m_pid, error.GetError(), error.AsCString()); + break; } - // Send the status. - bytes_written = 0; - error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written); - if (error.Fail() || (bytes_written < sizeof(status))) + // Log the successful result. + if (log) + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 + ", &status, 0) => %i, status = %i", + __FUNCTION__, m_pid, child_pid, status); + + // Handle the result. + if (WIFSTOPPED(status)) { + if (log) + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %" PRIu64 + ") received a stop, continuing waitpid() loop", + __FUNCTION__, m_pid); + continue; + } else // if (WIFEXITED(status) || WIFSIGNALED(status)) { - if (log) - log->Printf("NativeProcessDarwin::%s() - failed to write " - "waitpid exit result to the pipe. Client will not " - "hear about inferior exit status!", - __FUNCTION__); + if (log) + log->Printf("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; } - return error; + } + + // 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. + if (log) + log->Printf( + "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; } -Error -NativeProcessDarwin::HandleWaitpidResult() -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Read the pid. - const bool notify_status = true; +Error NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid, + int status) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - ::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))) - { - if (log) - log->Printf("NativeProcessDarwin::%s() - failed to read " - "waitpid exiting pid from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", - notify_status); - return error; - } + size_t bytes_written = 0; - // Read the status. - int status = -1; - error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read); - if (error.Fail() || (bytes_read < sizeof(status))) - { - if (log) - log->Printf("NativeProcessDarwin::%s() - failed to read " - "waitpid exit status from the pipe. Will notify " - "as if parent process died with exit status -1.", - __FUNCTION__); - SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", - notify_status); - return error; - } + // Send the pid. + error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written); + if (error.Fail() || (bytes_written < sizeof(pid))) { + if (log) + log->Printf("NativeProcessDarwin::%s() - failed to write " + "waitpid exiting pid to the pipe. Client will not " + "hear about inferior exit status!", + __FUNCTION__); + return error; + } - // Notify the monitor that our state has changed. + // Send the status. + bytes_written = 0; + error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written); + if (error.Fail() || (bytes_written < sizeof(status))) { if (log) - log->Printf("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); + log->Printf("NativeProcessDarwin::%s() - failed to write " + "waitpid exit result to the pipe. Client will not " + "hear about inferior exit status!", + __FUNCTION__); + } + return error; +} - ExitType exit_type = eExitTypeInvalid; - int exit_status = -1; +Error NativeProcessDarwin::HandleWaitpidResult() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (WIFEXITED(status)) - { - exit_type = eExitTypeExit; - exit_status = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - exit_type = eExitTypeSignal; - exit_status = WTERMSIG(status); - } + // 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))) { + if (log) + log->Printf("NativeProcessDarwin::%s() - failed to read " + "waitpid exiting pid from the pipe. Will notify " + "as if parent process died with exit status -1.", + __FUNCTION__); + SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", + notify_status); + return error; + } - SetExitStatus(exit_type, exit_status, nullptr, notify_status); + // Read the status. + int status = -1; + error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read); + if (error.Fail() || (bytes_read < sizeof(status))) { + if (log) + log->Printf("NativeProcessDarwin::%s() - failed to read " + "waitpid exit status from the pipe. Will notify " + "as if parent process died with exit status -1.", + __FUNCTION__); + SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", + notify_status); return error; + } + + // Notify the monitor that our state has changed. + if (log) + log->Printf("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); + + ExitType exit_type = eExitTypeInvalid; + int exit_status = -1; + + if (WIFEXITED(status)) { + exit_type = eExitTypeExit; + exit_status = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + exit_type = eExitTypeSignal; + exit_status = WTERMSIG(status); + } + + SetExitStatus(exit_type, exit_status, nullptr, notify_status); + return error; } -task_t -NativeProcessDarwin::TaskPortForProcessID(Error &error, bool force) const -{ - if ((m_task == TASK_NULL) || force) - { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (m_pid == LLDB_INVALID_PROCESS_ID) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): cannot get task due " - "to invalid pid", __FUNCTION__); - return TASK_NULL; - } +task_t NativeProcessDarwin::TaskPortForProcessID(Error &error, + bool force) const { + if ((m_task == TASK_NULL) || force) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (m_pid == LLDB_INVALID_PROCESS_ID) { + if (log) + log->Printf("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; - log->Printf("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) - { - log->Printf("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()); - } - } + const uint32_t num_retries = 10; + const uint32_t usec_interval = 10000; - // Sleep a bit and try again - ::usleep (usec_interval); + 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; + log->Printf("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) { + log->Printf("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()); } + } - // We failed to get the task for the inferior process. - // Ensure that it is cleared out. - m_task = TASK_NULL; + // Sleep a bit and try again + ::usleep(usec_interval); } - return m_task; -} -void -NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, - Error &error) -{ - error.SetErrorString("TODO: implement"); + // We failed to get the task for the inferior process. + // Ensure that it is cleared out. + m_task = TASK_NULL; + } + return m_task; } -Error -NativeProcessDarwin::PrivateResume() -{ - Error 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) - log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming (with " - "unhandled interrupt signal %i)...", __FUNCTION__, - m_task, m_auto_resume_signo); - else - log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming...", - __FUNCTION__, m_task); - } +void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, + Error &error) { + error.SetErrorString("TODO: implement"); +} - error = ReplyToAllExceptions(); - if (error.Fail()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): aborting, failed to " - "reply to exceptions: %s", __FUNCTION__, - error.AsCString()); - return error; - } - // bool stepOverBreakInstruction = step; +Error NativeProcessDarwin::PrivateResume() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - // 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); + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_mutex); + m_auto_resume_signo = m_sent_interrupt_signo; - // Set our state accordingly - if (m_thread_actions.NumActionsWithState(eStateStepping)) - SetState(eStateStepping); + if (log) { + if (m_auto_resume_signo) + log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming (with " + "unhandled interrupt signal %i)...", + __FUNCTION__, m_task, m_auto_resume_signo); else - SetState(eStateRunning); + log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming...", + __FUNCTION__, m_task); + } - // Now resume our task. - error = ResumeTask(); + error = ReplyToAllExceptions(); + if (error.Fail()) { + if (log) + log->Printf("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; } -Error -NativeProcessDarwin::ReplyToAllExceptions() -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_VERBOSE)); +Error NativeProcessDarwin::ReplyToAllExceptions() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - TaskPortForProcessID(error); - if (error.Fail()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): no task port, aborting", - __FUNCTION__); - return error; - } + TaskPortForProcessID(error); + if (error.Fail()) { + if (log) + log->Printf("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; + 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) { + log->Printf("NativeProcessDarwin::%s(): replying to exception " + "%zu...", + __FUNCTION__, index++); } - size_t index = 0; - for (auto &message : m_exception_messages) - { - if (log) - { - log->Printf("NativeProcessDarwin::%s(): replying to exception " - "%zu...", __FUNCTION__, index++); - } - - int thread_reply_signal = 0; + 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); + 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); - } + 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. - log->Printf("NativeProcessDarwin::%s(): failed to reply to " - "exception: %s", __FUNCTION__, error.AsCString()); - error.Clear(); - } + 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. + log->Printf("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; + // Erase all exception message as we should have used and replied + // to them all already. + m_exception_messages.clear(); + return error; } -Error -NativeProcessDarwin::ResumeTask() -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - TaskPortForProcessID(error); - if (error.Fail()) - { - if (log) - log->Printf("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; - } +Error NativeProcessDarwin::ResumeTask() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + TaskPortForProcessID(error); + if (error.Fail()) { if (log) - log->Printf("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()) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): failed to get task " - "BasicInfo when attempting to resume: %s", - __FUNCTION__, error.AsCString()); - return error; - } + log->Printf("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; + } + + if (log) + log->Printf("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()) { + if (log) + log->Printf("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()) - log->Printf("::task_resume(target_task = 0x%4.4x): success", - m_task); - else - log->Printf("::task_resume(target_task = 0x%4.4x) error: %s", - m_task, error.AsCString()); - } - } - else - { - if (log) - log->Printf("::task_resume(target_task = 0x%4.4x): ignored, " - "already running", m_task); + // 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()) + log->Printf("::task_resume(target_task = 0x%4.4x): success", m_task); + else + log->Printf("::task_resume(target_task = 0x%4.4x) error: %s", m_task, + error.AsCString()); } + } else { + if (log) + log->Printf("::task_resume(target_task = 0x%4.4x): ignored, " + "already running", + m_task); + } - return error; + return error; } -bool -NativeProcessDarwin::IsTaskValid() const -{ - if (m_task == TASK_NULL) - return false; +bool NativeProcessDarwin::IsTaskValid() const { + if (m_task == TASK_NULL) + return false; - struct task_basic_info task_info; - return GetTaskBasicInfo(m_task, &task_info).Success(); + 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; +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(); + struct task_basic_info task_info; + return GetTaskBasicInfo(task, &task_info).Success(); } -mach_port_t -NativeProcessDarwin::GetExceptionPort() const -{ - return m_exception_port; +mach_port_t NativeProcessDarwin::GetExceptionPort() const { + return m_exception_port; } -bool -NativeProcessDarwin::IsExceptionPortValid () const -{ - return MACH_PORT_VALID(m_exception_port); +bool NativeProcessDarwin::IsExceptionPortValid() const { + return MACH_PORT_VALID(m_exception_port); } -Error -NativeProcessDarwin::GetTaskBasicInfo(task_t task, - struct task_basic_info *info) const -{ - Error 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()) - { - if (log) - log->Printf("::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; - } +Error NativeProcessDarwin::GetTaskBasicInfo( + task_t task, struct task_basic_info *info) const { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - 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_log->Printf("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); - } + // 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()) { + if (log) + log->Printf("::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_log->Printf("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; } -Error -NativeProcessDarwin::SuspendTask() -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - if (m_task == TASK_NULL) - { - error.SetErrorString("task port is null, cannot suspend task"); - if (log) - log->Printf("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) - log->Printf("::task_suspend(target_task = 0x%4.4x)", m_task); +Error NativeProcessDarwin::SuspendTask() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (m_task == TASK_NULL) { + error.SetErrorString("task port is null, cannot suspend task"); + if (log) + log->Printf("NativeProcessDarwin::%s() failed: %s", __FUNCTION__, + error.AsCString()); return error; -} + } -Error -NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) -{ - Error error; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + auto mach_err = ::task_suspend(m_task); + error.SetError(mach_err, eErrorTypeMachKernel); + if (error.Fail() && log) + log->Printf("::task_suspend(target_task = 0x%4.4x)", m_task); - if (log) - log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__); + return error; +} - if (CanResume()) - { - m_thread_actions = resume_actions; - error = PrivateResume(); - return error; - } +Error NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - auto state = GetState(); - if (state == eStateRunning) - { - if (log) - log->Printf("NativeProcessDarwin::%s(): task 0x%x is already " - "running, ignoring...", __FUNCTION__, - TaskPortForProcessID(error)); - return error; - } + if (log) + log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__); - // We can't resume from this state. - error.SetErrorStringWithFormat("task 0x%x has state %s, can't resume", - TaskPortForProcessID(error), - StateAsCString(state)); + if (CanResume()) { + m_thread_actions = resume_actions; + error = PrivateResume(); return error; -} + } -Error -NativeProcessDarwin::Halt() -{ - Error error; - error.SetErrorString("TODO: implement"); + auto state = GetState(); + if (state == eStateRunning) { + if (log) + log->Printf("NativeProcessDarwin::%s(): task 0x%x is already " + "running, ignoring...", + __FUNCTION__, TaskPortForProcessID(error)); return error; -} + } -Error -NativeProcessDarwin::Detach() -{ - Error error; - error.SetErrorString("TODO: implement"); - 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; } -Error -NativeProcessDarwin::Signal(int signo) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::Halt() { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::Interrupt() -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::Detach() { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::Kill() -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::Signal(int signo) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::Interrupt() { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::Kill() { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, - size_t size, size_t &bytes_read) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf, - size_t size, size_t &bytes_written) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, + size_t size, + size_t &bytes_read) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -lldb::addr_t -NativeProcessDarwin::GetSharedLibraryInfoAddress() -{ - return LLDB_INVALID_ADDRESS; +Error NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions, + lldb::addr_t &addr) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -size_t -NativeProcessDarwin::UpdateThreads() -{ - return 0; +Error NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -bool -NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const -{ - return false; +lldb::addr_t NativeProcessDarwin::GetSharedLibraryInfoAddress() { + return LLDB_INVALID_ADDRESS; } -Error -NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +size_t NativeProcessDarwin::UpdateThreads() { return 0; } + +bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const { + return false; } -void -NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) -{ +Error NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::GetLoadedModuleFileSpec(const char* module_path, - FileSpec& file_spec) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +void NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId) {} + +Error NativeProcessDarwin::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } -Error -NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef& file_name, - lldb::addr_t& load_addr) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + Error error; + error.SetErrorString("TODO: implement"); + return error; } // ----------------------------------------------------------------- // NativeProcessProtocol protected interface // ----------------------------------------------------------------- -Error -NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode(size_t - trap_opcode_size_hint, - size_t &actual_opcode_size, - const uint8_t - *&trap_opcode_bytes) -{ - Error error; - error.SetErrorString("TODO: implement"); - return error; +Error NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode( + size_t trap_opcode_size_hint, size_t &actual_opcode_size, + const uint8_t *&trap_opcode_bytes) { + Error 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 index 13077452245..69c1b8d9e4c 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h +++ b/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.h @@ -23,217 +23,178 @@ // Other libraries and framework includes #include "lldb/Core/ArchSpec.h" -#include "lldb/lldb-types.h" -#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/Debug.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/Pipe.h" +#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/lldb-types.h" -#include "NativeThreadListDarwin.h" #include "LaunchFlavor.h" #include "MachException.h" #include "NativeThreadDarwin.h" +#include "NativeThreadListDarwin.h" namespace lldb_private { - class Error; - class Scalar; +class Error; +class Scalar; + +namespace process_darwin { + +/// @class NativeProcessDarwin +/// @brief 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 Error NativeProcessProtocol::Launch( + ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp); + + friend Error NativeProcessProtocol::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop, NativeProcessProtocolSP &process_sp); + +public: + ~NativeProcessDarwin() override; + + // ----------------------------------------------------------------- + // NativeProcessProtocol Interface + // ----------------------------------------------------------------- + Error Resume(const ResumeActionList &resume_actions) override; + + Error Halt() override; + + Error Detach() override; + + Error Signal(int signo) override; + + Error Interrupt() override; + + Error Kill() override; + + Error GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Error ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Error ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Error WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + Error AllocateMemory(size_t size, uint32_t permissions, + lldb::addr_t &addr) override; + + Error DeallocateMemory(lldb::addr_t addr) override; + + lldb::addr_t GetSharedLibraryInfoAddress() override; - namespace process_darwin { + size_t UpdateThreads() override; - /// @class NativeProcessDarwin - /// @brief 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 Error - NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info, - NativeDelegate &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp); - - friend Error - NativeProcessProtocol::Attach(lldb::pid_t pid, - NativeProcessProtocol::NativeDelegate - &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp); - - public: - - ~NativeProcessDarwin() override; - - // ----------------------------------------------------------------- - // NativeProcessProtocol Interface - // ----------------------------------------------------------------- - Error - Resume(const ResumeActionList &resume_actions) override; - - Error - Halt() override; - - Error - Detach() override; - - Error - Signal(int signo) override; - - Error - Interrupt() override; - - Error - Kill() override; - - Error - GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo - &range_info) override; - - Error - ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Error - ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Error - WriteMemory(lldb::addr_t addr, const void *buf, size_t size, - size_t &bytes_written) override; - - Error - AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Error - DeallocateMemory(lldb::addr_t addr) override; - - lldb::addr_t - GetSharedLibraryInfoAddress() override; - - size_t - UpdateThreads() override; - - bool - GetArchitecture(ArchSpec &arch) const override; - - Error - SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) override; - - void - DoStopIDBumped(uint32_t newBumpId) override; - - Error - GetLoadedModuleFileSpec(const char* module_path, - FileSpec& file_spec) override; - - Error - 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 Error - PtraceWrapper(int req, - lldb::pid_t pid, - void *addr = nullptr, - void *data = nullptr, - size_t data_size = 0, - long *result = nullptr); + bool GetArchitecture(ArchSpec &arch) const override; - bool - SupportHardwareSingleStepping() const; + Error SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override; - protected: - // ----------------------------------------------------------------- - // NativeProcessProtocol protected interface - // ----------------------------------------------------------------- - Error - GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, - size_t &actual_opcode_size, - const uint8_t *&trap_opcode_bytes) - override; + void DoStopIDBumped(uint32_t newBumpId) override; - private: + Error GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; - // ----------------------------------------------------------------- - /// Mach task-related Member Variables - // ----------------------------------------------------------------- + Error GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; - // The task port for the inferior process. - mutable task_t m_task; + NativeThreadDarwinSP GetThreadByID(lldb::tid_t id); - // True if the inferior process did an exec since we started - // monitoring it. - bool m_did_exec; + task_t GetTask() const { return m_task; } - // The CPU type of this process. - mutable cpu_type_t m_cpu_type; + // ----------------------------------------------------------------- + // Interface used by NativeRegisterContext-derived classes. + // ----------------------------------------------------------------- + static Error PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + void *data = nullptr, size_t data_size = 0, + long *result = nullptr); - // ----------------------------------------------------------------- - /// Exception/Signal Handling Member Variables - // ----------------------------------------------------------------- + bool SupportHardwareSingleStepping() const; - // Exception port on which we will receive child exceptions - mach_port_t m_exception_port; +protected: + // ----------------------------------------------------------------- + // NativeProcessProtocol protected interface + // ----------------------------------------------------------------- + Error + GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, + size_t &actual_opcode_size, + const uint8_t *&trap_opcode_bytes) override; - // Saved state of the child exception port prior to us installing - // our own intercepting port. - MachException::PortInfo m_exc_port_info; +private: + // ----------------------------------------------------------------- + /// Mach task-related Member Variables + // ----------------------------------------------------------------- - // The thread that runs the Mach exception read and reply handler. - pthread_t m_exception_thread; + // The task port for the inferior process. + mutable task_t m_task; - // 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; + // True if the inferior process did an exec since we started + // monitoring it. + bool m_did_exec; - // A collection of exception messages caught when listening to the - // exception port. - MachException::Message::collection m_exception_messages; + // The CPU type of this process. + mutable cpu_type_t m_cpu_type; - // When we call MachProcess::Interrupt(), we want to send this - // signal (if non-zero). - int m_sent_interrupt_signo; + // ----------------------------------------------------------------- + /// Exception/Signal Handling Member Variables + // ----------------------------------------------------------------- - // If we resume the process and still haven't received our - // interrupt signal (if this is non-zero). - int m_auto_resume_signo; + // Exception port on which we will receive child exceptions + mach_port_t m_exception_port; - // ----------------------------------------------------------------- - /// Thread-related Member Variables - // ----------------------------------------------------------------- - NativeThreadListDarwin m_thread_list; - ResumeActionList m_thread_actions; + // Saved state of the child exception port prior to us installing + // our own intercepting port. + MachException::PortInfo m_exc_port_info; - // ----------------------------------------------------------------- - /// Process Lifetime Member Variable - // ----------------------------------------------------------------- + // The thread that runs the Mach exception read and reply handler. + pthread_t m_exception_thread; - // 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; + // 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; #if 0 ArchSpec m_arch; @@ -249,158 +210,116 @@ namespace lldb_private { m_threads_stepping_with_breakpoint; #endif - // ----------------------------------------------------------------- - // Private Instance Methods - // ----------------------------------------------------------------- - NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd); + // ----------------------------------------------------------------- + // 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. - // ----------------------------------------------------------------- - Error - FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop); + // ----------------------------------------------------------------- + /// 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. + // ----------------------------------------------------------------- + Error FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop &main_loop); - Error - SaveExceptionPortInfo(); + Error SaveExceptionPortInfo(); - void - ExceptionMessageReceived(const MachException::Message &message); + void ExceptionMessageReceived(const MachException::Message &message); - void - MaybeRaiseThreadPriority(); + void MaybeRaiseThreadPriority(); - Error - StartExceptionThread(); + Error StartExceptionThread(); - Error - SendInferiorExitStatusToMainLoop(::pid_t pid, int status); + Error SendInferiorExitStatusToMainLoop(::pid_t pid, int status); - Error - HandleWaitpidResult(); + Error HandleWaitpidResult(); - bool - ProcessUsingSpringBoard() const; + bool ProcessUsingSpringBoard() const; - bool - ProcessUsingBackBoard() const; + bool ProcessUsingBackBoard() const; - static void* - ExceptionThread(void *arg); + static void *ExceptionThread(void *arg); - void* - DoExceptionThread(); + void *DoExceptionThread(); - lldb::addr_t - GetDYLDAllImageInfosAddress(Error &error) const; + lldb::addr_t GetDYLDAllImageInfosAddress(Error &error) const; - static uint32_t - GetCPUTypeForLocalProcess(::pid_t pid); + static uint32_t GetCPUTypeForLocalProcess(::pid_t pid); - uint32_t - GetCPUType() const; + uint32_t GetCPUType() const; - task_t - ExceptionMessageBundleComplete(); + task_t ExceptionMessageBundleComplete(); - void - StartSTDIOThread(); + void StartSTDIOThread(); - Error - StartWaitpidThread(MainLoop &main_loop); + Error StartWaitpidThread(MainLoop &main_loop); - static void* - WaitpidThread(void *arg); + static void *WaitpidThread(void *arg); - void* - DoWaitpidThread(); + void *DoWaitpidThread(); - task_t - TaskPortForProcessID(Error &error, bool force = false) const; + task_t TaskPortForProcessID(Error &error, bool force = false) const; - /// Attaches to an existing process. Forms the - /// implementation of Process::DoAttach. - void - AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error &error); + /// Attaches to an existing process. Forms the + /// implementation of Process::DoAttach. + void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error &error); - ::pid_t - Attach(lldb::pid_t pid, Error &error); + ::pid_t Attach(lldb::pid_t pid, Error &error); - Error - PrivateResume(); + Error PrivateResume(); - Error - ReplyToAllExceptions(); + Error ReplyToAllExceptions(); - Error - ResumeTask(); + Error ResumeTask(); - bool - IsTaskValid() const; + bool IsTaskValid() const; - bool - IsTaskValid(task_t task) const; + bool IsTaskValid(task_t task) const; - mach_port_t - GetExceptionPort() const; + mach_port_t GetExceptionPort() const; - bool - IsExceptionPortValid () const; + bool IsExceptionPortValid() const; - Error - GetTaskBasicInfo(task_t task, struct task_basic_info *info) const; + Error GetTaskBasicInfo(task_t task, struct task_basic_info *info) const; - Error - SuspendTask(); + Error SuspendTask(); - static Error - SetDefaultPtraceOpts(const lldb::pid_t); + static Error SetDefaultPtraceOpts(const lldb::pid_t); - static void * - MonitorThread(void *baton); + static void *MonitorThread(void *baton); - void - MonitorCallback(lldb::pid_t pid, bool exited, int signal, - int status); + void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status); - void - WaitForNewThread(::pid_t tid); + void WaitForNewThread(::pid_t tid); - void - MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin &thread); + void MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin &thread); - void - MonitorTrace(NativeThreadDarwin &thread); + void MonitorTrace(NativeThreadDarwin &thread); - void - MonitorBreakpoint(NativeThreadDarwin &thread); + void MonitorBreakpoint(NativeThreadDarwin &thread); - void - MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t wp_index); + void MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t wp_index); - void - MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread, - bool exited); + void MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread, + bool exited); - Error - SetupSoftwareSingleStepping(NativeThreadDarwin &thread); + Error SetupSoftwareSingleStepping(NativeThreadDarwin &thread); #if 0 static ::ProcessMessage::CrashReason @@ -416,64 +335,50 @@ namespace lldb_private { GetCrashReasonForSIGBUS(const siginfo_t *info); #endif - bool - HasThreadNoLock(lldb::tid_t thread_id); - - bool - StopTrackingThread(lldb::tid_t thread_id); - - NativeThreadDarwinSP - AddThread(lldb::tid_t thread_id); - - Error - GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); - - Error - FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread); - - /// Writes a siginfo_t structure corresponding to the given thread - /// ID to the memory region pointed to by @p siginfo. - Error - 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. - Error - GetEventMessage(lldb::tid_t tid, unsigned long *message); - - void - NotifyThreadDeath(lldb::tid_t tid); - - Error - 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. - Error - ResumeThread(NativeThreadDarwin &thread, lldb::StateType state, - int signo); - - void - ThreadWasCreated(NativeThreadDarwin &thread); - - void - SigchldHandler(); - }; - - } // namespace process_darwin + bool HasThreadNoLock(lldb::tid_t thread_id); + + bool StopTrackingThread(lldb::tid_t thread_id); + + NativeThreadDarwinSP AddThread(lldb::tid_t thread_id); + + Error GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); + + Error FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread); + + /// Writes a siginfo_t structure corresponding to the given thread + /// ID to the memory region pointed to by @p siginfo. + Error 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. + Error GetEventMessage(lldb::tid_t tid, unsigned long *message); + + void NotifyThreadDeath(lldb::tid_t tid); + + Error 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. + Error 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 index 08d1a8da92b..5e7f9ae7e6f 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp +++ b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp @@ -21,117 +21,94 @@ 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; +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; + ::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; +std::string NativeThreadDarwin::GetName() { + std::string name; - if (GetIdentifierInfo()) - { - auto process_sp = GetProcess(); - if (!process_sp) - { - name = "<unavailable>"; - return 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)); + 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; + if (len && m_proc_threadinfo.pth_name[0]) + name = m_proc_threadinfo.pth_name; + } + return name; } -lldb::StateType -NativeThreadDarwin::GetState() -{ - // TODO implement - return eStateInvalid; +lldb::StateType NativeThreadDarwin::GetState() { + // TODO implement + return eStateInvalid; } -bool -NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, - std::string& description) -{ - // TODO implement - return false; +bool NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + // TODO implement + return false; } -NativeRegisterContextSP -NativeThreadDarwin::GetRegisterContext() -{ - // TODO implement - return NativeRegisterContextSP(); +NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() { + // TODO implement + return NativeRegisterContextSP(); } -Error -NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags, bool hardware) -{ - Error error; - error.SetErrorString("not yet implemented"); - return error; +Error NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + Error error; + error.SetErrorString("not yet implemented"); + return error; } -Error -NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) -{ - Error error; - error.SetErrorString("not yet implemented"); - return error; +Error NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) { + Error 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. +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, @@ -150,16 +127,14 @@ NativeThreadDarwin::Dump(Stream &stream) const 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); + // 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. +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. @@ -182,15 +157,13 @@ NativeThreadDarwin::NotifyException(MachException::Data &exc) return handled; #else - // Pretend we handled it. - return true; + // Pretend we handled it. + return true; #endif } -bool -NativeThreadDarwin::ShouldStop(bool &step_more) const -{ - // TODO: implement this +bool NativeThreadDarwin::ShouldStop(bool &step_more) const { +// TODO: implement this #if 0 // See if this thread is at a breakpoint? DNBBreakpoint *bp = CurrentBreakpoint(); @@ -229,14 +202,12 @@ NativeThreadDarwin::ShouldStop(bool &step_more) const } return false; #else - return false; + return false; #endif } -void -NativeThreadDarwin::ThreadDidStop() -{ - // TODO implement this. +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 @@ -267,58 +238,47 @@ NativeThreadDarwin::ThreadDidStop() #endif } -bool -NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread) -{ - return thread != (::thread_t)(0); +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; +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::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(); +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; + 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()); +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 index efdf79ac3e0..b8d9089e673 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h +++ b/lldb/source/Plugins/Process/Darwin/NativeThreadDarwin.h @@ -21,8 +21,8 @@ #include <string> // LLDB includes -#include "lldb/lldb-private-forward.h" #include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" #include "MachException.h" @@ -34,168 +34,130 @@ using NativeProcessDarwinSP = std::shared_ptr<NativeProcessDarwin>; class NativeThreadListDarwin; -class NativeThreadDarwin : public NativeThreadProtocol -{ - friend class NativeProcessDarwin; - friend class NativeThreadListDarwin; +class NativeThreadDarwin : public NativeThreadProtocol { + friend class NativeProcessDarwin; + friend class NativeThreadListDarwin; public: + static uint64_t + GetGloballyUniqueThreadIDForMachPortID(::thread_t mach_port_id); - 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); + 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; + // ----------------------------------------------------------------- + // NativeThreadProtocol Interface + // ----------------------------------------------------------------- + std::string GetName() override; - lldb::StateType - GetState () override; + lldb::StateType GetState() override; - bool - GetStopReason(ThreadStopInfo &stop_info, - std::string& description) override; + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; - NativeRegisterContextSP - GetRegisterContext() override; + NativeRegisterContextSP GetRegisterContext() override; - Error - SetWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags, bool hardware) override; + Error SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; - Error - RemoveWatchpoint(lldb::addr_t addr) override; + Error RemoveWatchpoint(lldb::addr_t addr) override; - // ----------------------------------------------------------------- - // New methods that are fine for others to call. - // ----------------------------------------------------------------- - void - Dump(Stream &stream) const; + // ----------------------------------------------------------------- + // New methods that are fine for others to call. + // ----------------------------------------------------------------- + void Dump(Stream &stream) const; private: - // ----------------------------------------------------------------- - // Interface for friend classes - // ----------------------------------------------------------------- + // ----------------------------------------------------------------- + // Interface for friend classes + // ----------------------------------------------------------------- - /// Resumes the thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Error - Resume(uint32_t signo); + /// Resumes the thread. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Error Resume(uint32_t signo); - /// Single steps the thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Error - SingleStep(uint32_t signo); + /// Single steps the thread. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + Error SingleStep(uint32_t signo); - bool - NotifyException(MachException::Data &exc); + bool NotifyException(MachException::Data &exc); - bool - ShouldStop(bool &step_more) const; + bool ShouldStop(bool &step_more) const; - void - ThreadDidStop(); + void ThreadDidStop(); - void - SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + 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); + /// 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; + const struct thread_basic_info *GetBasicInfo() const; - static bool - GetBasicInfo(::thread_t thread, struct thread_basic_info *basicInfoPtr); + static bool GetBasicInfo(::thread_t thread, + struct thread_basic_info *basicInfoPtr); - bool - IsUserReady() const; + bool IsUserReady() const; - void - SetStoppedByExec (); + void SetStoppedByExec(); - void - SetStoppedByBreakpoint (); + void SetStoppedByBreakpoint(); - void - SetStoppedByWatchpoint (uint32_t wp_index); + void SetStoppedByWatchpoint(uint32_t wp_index); - bool - IsStoppedAtBreakpoint (); + bool IsStoppedAtBreakpoint(); - bool - IsStoppedAtWatchpoint (); + bool IsStoppedAtWatchpoint(); - void - SetStoppedByTrace (); + void SetStoppedByTrace(); - void - SetStoppedWithNoReason (); + void SetStoppedWithNoReason(); - void - SetExited (); + void SetExited(); - Error - RequestStop (); + Error 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; - } + // ------------------------------------------------------------------------- + /// 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); + static bool MachPortNumberIsValid(::thread_t thread); - // --------------------------------------------------------------------- - // Private interface - // --------------------------------------------------------------------- - bool - GetIdentifierInfo(); + // --------------------------------------------------------------------- + // Private interface + // --------------------------------------------------------------------- + bool GetIdentifierInfo(); - void - MaybeLogStateChange (lldb::StateType new_state); + void MaybeLogStateChange(lldb::StateType new_state); - NativeProcessDarwinSP - GetNativeProcessDarwinSP(); + NativeProcessDarwinSP GetNativeProcessDarwinSP(); - void - SetStopped(); + void SetStopped(); - inline void - MaybePrepareSingleStepWorkaround(); + inline void MaybePrepareSingleStepWorkaround(); - inline void - MaybeCleanupSingleStepWorkaround(); + inline void MaybeCleanupSingleStepWorkaround(); - // ----------------------------------------------------------------- - // Member Variables - // ----------------------------------------------------------------- + // ----------------------------------------------------------------- + // Member Variables + // ----------------------------------------------------------------- - // The mach thread port for the thread. - ::thread_t m_mach_thread_port; + // 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; + // The most recently-retrieved thread basic info. + mutable ::thread_basic_info m_basic_info; - struct proc_threadinfo m_proc_threadinfo; + struct proc_threadinfo m_proc_threadinfo; - thread_identifier_info_data_t m_ident_info; + thread_identifier_info_data_t m_ident_info; #if 0 lldb::StateType m_state; diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp index 034c0c9f1fa..aa9b0415765 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp +++ b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp @@ -1,4 +1,5 @@ -//===-- NativeThreadListDarwin.cpp ------------------------------------*- C++ -*-===// +//===-- NativeThreadListDarwin.cpp ------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -31,16 +32,10 @@ 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() + : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} -NativeThreadListDarwin::~NativeThreadListDarwin() -{ -} +NativeThreadListDarwin::~NativeThreadListDarwin() {} // These methods will be accessed directly from NativeThreadDarwin #if 0 @@ -155,41 +150,33 @@ NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const #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; +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 @@ -267,11 +254,9 @@ NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t save_id } #endif -size_t -NativeThreadListDarwin::GetNumberOfThreads() const -{ - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - return static_cast<size_t>(m_threads.size()); +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 @@ -297,149 +282,129 @@ NativeThreadListDarwin::CurrentThreadID ( ) #endif -bool -NativeThreadListDarwin::NotifyException(MachException::Data &exc) -{ - auto thread_sp = GetThreadByMachPortNumber(exc.thread_port); - if (thread_sp) - { - thread_sp->NotifyException(exc); - return true; +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); + if (log) + log->Printf("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; } - 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); - if (log) - log->Printf("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 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__) +#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(); + + Error error; + auto mach_err = ::task_threads(task, &thread_list, &thread_list_count); + error.SetError(mach_err, eErrorTypeMachKernel); + if (error.Fail()) { + if (log) + log->Printf("::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 (m_threads.empty() || update) - { - thread_array_t thread_list = nullptr; - mach_msg_type_number_t thread_list_count = 0; - task_t task = process.GetTask(); - - Error error; - auto mach_err = ::task_threads(task, &thread_list, &thread_list_count); - error.SetError(mach_err, eErrorTypeMachKernel); - if (error.Fail()) - { - if (log) - log->Printf("::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); - } - } - } + 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(); + 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); - } + // 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()); + } + return static_cast<uint32_t>(m_threads.size()); } // TODO implement @@ -470,37 +435,31 @@ NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) #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::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); +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; + // 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. +// 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. @@ -526,7 +485,7 @@ NativeThreadListDarwin::ProcessWillResume(NativeProcessDarwin &process, run_one_thread = false; #endif - UpdateThreadList(process, true, &new_threads); + UpdateThreadList(process, true, &new_threads); #if 0 DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; @@ -576,20 +535,17 @@ NativeThreadListDarwin::ProcessWillResume(NativeProcessDarwin &process, #endif } -uint32_t -NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) -{ - std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); +uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); - // Update our thread list. - UpdateThreadList(process, true); + // 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(); + for (auto thread_sp : m_threads) { + if (thread_sp) + thread_sp->ThreadDidStop(); + } + return (uint32_t)m_threads.size(); } //---------------------------------------------------------------------- @@ -603,16 +559,13 @@ NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) // 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; +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. diff --git a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h index 588013043e1..2b194bcc153 100644 --- a/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h +++ b/lldb/source/Plugins/Process/Darwin/NativeThreadListDarwin.h @@ -1,4 +1,5 @@ -//===-- NativeThreadListDarwin.h --------------------------------------*- C++ -*-===// +//===-- NativeThreadListDarwin.h --------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -34,19 +35,16 @@ class NativeProcessDarwin; class NativeThreadDarwin; using NativeThreadDarwinSP = std::shared_ptr<NativeThreadDarwin>; -class NativeThreadListDarwin -{ +class NativeThreadListDarwin { public: - NativeThreadListDarwin(); - ~NativeThreadListDarwin(); + NativeThreadListDarwin(); + ~NativeThreadListDarwin(); - void - Clear(); + void Clear(); - void - Dump(Stream &stream) const; + void Dump(Stream &stream) const; - // These methods will be accessed directly from NativeThreadDarwin +// 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; @@ -56,30 +54,25 @@ public: bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); #endif - const char * - GetThreadInfo(lldb::tid_t tid) const; + const char *GetThreadInfo(lldb::tid_t tid) const; - void - ProcessWillResume(NativeProcessDarwin &process, - const ResumeActionList &thread_actions); + void ProcessWillResume(NativeProcessDarwin &process, + const ResumeActionList &thread_actions); - uint32_t - ProcessDidStop(NativeProcessDarwin &process); + uint32_t ProcessDidStop(NativeProcessDarwin &process); - bool - NotifyException(MachException::Data& exc); + bool NotifyException(MachException::Data &exc); - bool - ShouldStop(bool &step_more); + bool ShouldStop(bool &step_more); - // These methods will be accessed directly from NativeThreadDarwin +// 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. +// 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); @@ -87,76 +80,60 @@ public: 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 +// 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; + size_t GetNumberOfThreads() const; - lldb::tid_t - ThreadIDAtIndex(size_t idx) const; + lldb::tid_t ThreadIDAtIndex(size_t idx) const; - lldb::tid_t - GetCurrentThreadID(); + lldb::tid_t GetCurrentThreadID(); - NativeThreadDarwinSP - GetCurrentThread(); + NativeThreadDarwinSP GetCurrentThread(); - void - NotifyBreakpointChanged(const NativeBreakpointDarwin *bp); + void NotifyBreakpointChanged(const NativeBreakpointDarwin *bp); - uint32_t - EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; + uint32_t EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - bool - DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; + bool DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; - uint32_t - EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; + uint32_t EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - bool - DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; + bool DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; - uint32_t - GetNumberOfSupportedHardwareWatchpoints() const; + uint32_t GetNumberOfSupportedHardwareWatchpoints() const; - size_t - GetThreadIndexForThreadStoppedWithSignal(const int signo) const; + size_t GetThreadIndexForThreadStoppedWithSignal(const int signo) const; - NativeThreadDarwinSP - GetThreadByID(lldb::tid_t tid) const; + NativeThreadDarwinSP GetThreadByID(lldb::tid_t tid) const; - NativeThreadDarwinSP - GetThreadByMachPortNumber(::thread_t mach_port_number) const; + NativeThreadDarwinSP + GetThreadByMachPortNumber(::thread_t mach_port_number) const; - lldb::tid_t - GetThreadIDByMachPortNumber(::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; + 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::Error. - 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; + typedef std::vector<NativeThreadDarwinSP> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + // Consider having this return an lldb_private::Error. + 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__ - |