diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Plugins/Process/Darwin | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
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__ - |