diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /source/Plugins/Process | |
parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
download | src-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz src-14f1b3e8826ce43b978db93a62d1166055db5394.zip |
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=311128
svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'source/Plugins/Process')
295 files changed, 64303 insertions, 61823 deletions
diff --git a/source/Plugins/Process/CMakeLists.txt b/source/Plugins/Process/CMakeLists.txt index d15df94414b3..defa493088b6 100644 --- a/source/Plugins/Process/CMakeLists.txt +++ b/source/Plugins/Process/CMakeLists.txt @@ -7,8 +7,6 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") - add_subdirectory(Windows/Live) - add_subdirectory(Windows/MiniDump) add_subdirectory(Windows/Common) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(MacOSX-Kernel) @@ -17,3 +15,4 @@ add_subdirectory(gdb-remote) add_subdirectory(Utility) add_subdirectory(mach-core) add_subdirectory(elf-core) +add_subdirectory(minidump) diff --git a/source/Plugins/Process/Darwin/CFBundle.cpp b/source/Plugins/Process/Darwin/CFBundle.cpp new file mode 100644 index 000000000000..7b080e60cdb3 --- /dev/null +++ b/source/Plugins/Process/Darwin/CFBundle.cpp @@ -0,0 +1,79 @@ +//===-- CFBundle.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 1/16/08. +// +//===----------------------------------------------------------------------===// + +#include "CFBundle.h" +#include "CFString.h" + +//---------------------------------------------------------------------- +// CFBundle constructor +//---------------------------------------------------------------------- +CFBundle::CFBundle(const char *path) + : CFReleaser<CFBundleRef>(), m_bundle_url() { + if (path && path[0]) + SetPath(path); +} + +//---------------------------------------------------------------------- +// CFBundle copy constructor +//---------------------------------------------------------------------- +CFBundle::CFBundle(const CFBundle &rhs) + : CFReleaser<CFBundleRef>(rhs), m_bundle_url(rhs.m_bundle_url) {} + +//---------------------------------------------------------------------- +// CFBundle copy constructor +//---------------------------------------------------------------------- +CFBundle &CFBundle::operator=(const CFBundle &rhs) { + *this = rhs; + return *this; +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CFBundle::~CFBundle() {} + +//---------------------------------------------------------------------- +// Set the path for a bundle by supplying a +//---------------------------------------------------------------------- +bool CFBundle::SetPath(const char *path) { + CFAllocatorRef alloc = kCFAllocatorDefault; + // Release our old bundle and ULR + reset(); // This class is a CFReleaser<CFBundleRef> + m_bundle_url.reset(); + // Make a CFStringRef from the supplied path + CFString cf_path; + cf_path.SetFileSystemRepresentation(path); + if (cf_path.get()) { + // Make our Bundle URL + m_bundle_url.reset(::CFURLCreateWithFileSystemPath( + alloc, cf_path.get(), kCFURLPOSIXPathStyle, true)); + if (m_bundle_url.get()) { + reset(::CFBundleCreate(alloc, m_bundle_url.get())); + } + } + return get() != NULL; +} + +CFStringRef CFBundle::GetIdentifier() const { + CFBundleRef bundle = get(); + if (bundle != NULL) + return ::CFBundleGetIdentifier(bundle); + return NULL; +} + +CFURLRef CFBundle::CopyExecutableURL() const { + CFBundleRef bundle = get(); + if (bundle != NULL) + return CFBundleCopyExecutableURL(bundle); + return NULL; +} diff --git a/source/Plugins/Process/Darwin/CFBundle.h b/source/Plugins/Process/Darwin/CFBundle.h new file mode 100644 index 000000000000..09957af534b3 --- /dev/null +++ b/source/Plugins/Process/Darwin/CFBundle.h @@ -0,0 +1,38 @@ +//===-- CFBundle.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 1/16/08. +// +//===----------------------------------------------------------------------===// + +#ifndef __CFBundle_h__ +#define __CFBundle_h__ + +#include "CFUtils.h" + +class CFBundle : public CFReleaser<CFBundleRef> { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CFBundle(const char *path = NULL); + CFBundle(const CFBundle &rhs); + CFBundle &operator=(const CFBundle &rhs); + virtual ~CFBundle(); + bool SetPath(const char *path); + + CFStringRef GetIdentifier() const; + + CFURLRef CopyExecutableURL() const; + +protected: + CFReleaser<CFURLRef> m_bundle_url; +}; + +#endif // #ifndef __CFBundle_h__ diff --git a/source/Plugins/Process/Darwin/CFString.cpp b/source/Plugins/Process/Darwin/CFString.cpp new file mode 100644 index 000000000000..84ad56774d7c --- /dev/null +++ b/source/Plugins/Process/Darwin/CFString.cpp @@ -0,0 +1,163 @@ +//===-- CFString.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 1/16/08. +// +//===----------------------------------------------------------------------===// + +#include "CFString.h" +#include <glob.h> +#include <string> + +//---------------------------------------------------------------------- +// CFString constructor +//---------------------------------------------------------------------- +CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {} + +//---------------------------------------------------------------------- +// CFString copy constructor +//---------------------------------------------------------------------- +CFString::CFString(const CFString &rhs) : CFReleaser<CFStringRef>(rhs) {} + +//---------------------------------------------------------------------- +// CFString copy constructor +//---------------------------------------------------------------------- +CFString &CFString::operator=(const CFString &rhs) { + if (this != &rhs) + *this = rhs; + return *this; +} + +CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding) + : CFReleaser<CFStringRef>() { + if (cstr && cstr[0]) { + reset( + ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); + } +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CFString::~CFString() {} + +const char *CFString::GetFileSystemRepresentation(std::string &s) { + return CFString::FileSystemRepresentation(get(), s); +} + +CFStringRef CFString::SetFileSystemRepresentation(const char *path) { + CFStringRef new_value = NULL; + if (path && path[0]) + new_value = + ::CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); + reset(new_value); + return get(); +} + +CFStringRef CFString::SetFileSystemRepresentationFromCFType(CFTypeRef cf_type) { + CFStringRef new_value = NULL; + if (cf_type != NULL) { + CFTypeID cf_type_id = ::CFGetTypeID(cf_type); + + if (cf_type_id == ::CFStringGetTypeID()) { + // Retain since we are using the existing object + new_value = (CFStringRef)::CFRetain(cf_type); + } else if (cf_type_id == ::CFURLGetTypeID()) { + new_value = + ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle); + } + } + reset(new_value); + return get(); +} + +CFStringRef +CFString::SetFileSystemRepresentationAndExpandTilde(const char *path) { + std::string expanded_path; + if (CFString::GlobPath(path, expanded_path)) + SetFileSystemRepresentation(expanded_path.c_str()); + else + reset(); + return get(); +} + +const char *CFString::UTF8(std::string &str) { + return CFString::UTF8(get(), str); +} + +// Static function that puts a copy of the UTF8 contents of CF_STR into STR +// and returns the C string pointer that is contained in STR when successful, +// else +// NULL is returned. This allows the std::string parameter to own the extracted +// string, +// and also allows that string to be returned as a C string pointer that can be +// used. + +const char *CFString::UTF8(CFStringRef cf_str, std::string &str) { + if (cf_str) { + const CFStringEncoding encoding = kCFStringEncodingUTF8; + CFIndex max_utf8_str_len = CFStringGetLength(cf_str); + max_utf8_str_len = + CFStringGetMaximumSizeForEncoding(max_utf8_str_len, encoding); + if (max_utf8_str_len > 0) { + str.resize(max_utf8_str_len); + if (!str.empty()) { + if (CFStringGetCString(cf_str, &str[0], str.size(), encoding)) { + str.resize(strlen(str.c_str())); + return str.c_str(); + } + } + } + } + return NULL; +} + +// Static function that puts a copy of the file system representation of CF_STR +// into STR and returns the C string pointer that is contained in STR when +// successful, else NULL is returned. This allows the std::string parameter +// to own the extracted string, and also allows that string to be returned as +// a C string pointer that can be used. + +const char *CFString::FileSystemRepresentation(CFStringRef cf_str, + std::string &str) { + if (cf_str) { + CFIndex max_length = + ::CFStringGetMaximumSizeOfFileSystemRepresentation(cf_str); + if (max_length > 0) { + str.resize(max_length); + if (!str.empty()) { + if (::CFStringGetFileSystemRepresentation(cf_str, &str[0], + str.size())) { + str.erase(::strlen(str.c_str())); + return str.c_str(); + } + } + } + } + str.erase(); + return NULL; +} + +CFIndex CFString::GetLength() const { + CFStringRef str = get(); + if (str) + return CFStringGetLength(str); + return 0; +} + +const char *CFString::GlobPath(const char *path, std::string &expanded_path) { + glob_t globbuf; + if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) { + expanded_path = globbuf.gl_pathv[0]; + ::globfree(&globbuf); + } else + expanded_path.clear(); + + return expanded_path.c_str(); +} diff --git a/source/Plugins/Process/Darwin/CFString.h b/source/Plugins/Process/Darwin/CFString.h new file mode 100644 index 000000000000..18d60a5a74bd --- /dev/null +++ b/source/Plugins/Process/Darwin/CFString.h @@ -0,0 +1,43 @@ +//===-- CFString.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 1/16/08. +// +//===----------------------------------------------------------------------===// + +#ifndef __CFString_h__ +#define __CFString_h__ + +#include "CFUtils.h" +#include <iosfwd> + +class CFString : public CFReleaser<CFStringRef> { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CFString(CFStringRef cf_str = NULL); + CFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); + CFString(const CFString &rhs); + CFString &operator=(const CFString &rhs); + virtual ~CFString(); + + const char *GetFileSystemRepresentation(std::string &str); + CFStringRef SetFileSystemRepresentation(const char *path); + CFStringRef SetFileSystemRepresentationFromCFType(CFTypeRef cf_type); + CFStringRef SetFileSystemRepresentationAndExpandTilde(const char *path); + const char *UTF8(std::string &str); + CFIndex GetLength() const; + static const char *UTF8(CFStringRef cf_str, std::string &str); + static const char *FileSystemRepresentation(CFStringRef cf_str, + std::string &str); + static const char *GlobPath(const char *path, std::string &expanded_path); +}; + +#endif // #ifndef __CFString_h__ diff --git a/source/Plugins/Process/Darwin/CFUtils.h b/source/Plugins/Process/Darwin/CFUtils.h new file mode 100644 index 000000000000..a904cd0ea6f0 --- /dev/null +++ b/source/Plugins/Process/Darwin/CFUtils.h @@ -0,0 +1,78 @@ +//===-- CFUtils.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 3/5/07. +// +//===----------------------------------------------------------------------===// + +#ifndef __CFUtils_h__ +#define __CFUtils_h__ + +#include <CoreFoundation/CoreFoundation.h> + +#ifdef __cplusplus + +//---------------------------------------------------------------------- +// Templatized CF helper class that can own any CF pointer and will +// call CFRelease() on any valid pointer it owns unless that pointer is +// explicitly released using the release() member function. +//---------------------------------------------------------------------- +template <class T> class CFReleaser { +public: + // Type names for the avlue + typedef T element_type; + + // Constructors and destructors + CFReleaser(T ptr = NULL) : _ptr(ptr) {} + CFReleaser(const CFReleaser ©) : _ptr(copy.get()) { + if (get()) + ::CFRetain(get()); + } + virtual ~CFReleaser() { reset(); } + + // Assignments + CFReleaser &operator=(const CFReleaser<T> ©) { + if (copy != *this) { + // Replace our owned pointer with the new one + reset(copy.get()); + // Retain the current pointer that we own + if (get()) + ::CFRetain(get()); + } + } + // Get the address of the contained type + T *ptr_address() { return &_ptr; } + + // Access the pointer itself + const T get() const { return _ptr; } + T get() { return _ptr; } + + // Set a new value for the pointer and CFRelease our old + // value if we had a valid one. + void reset(T ptr = NULL) { + if (ptr != _ptr) { + if (_ptr != NULL) + ::CFRelease(_ptr); + _ptr = ptr; + } + } + + // Release ownership without calling CFRelease + T release() { + T tmp = _ptr; + _ptr = NULL; + return tmp; + } + +private: + element_type _ptr; +}; + +#endif // #ifdef __cplusplus +#endif // #ifndef __CFUtils_h__ diff --git a/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp new file mode 100644 index 000000000000..63b1ae6da968 --- /dev/null +++ b/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp @@ -0,0 +1,653 @@ +//===-- DarwinProcessLauncher.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// +// DarwinProcessLauncher.cpp +// lldb +// +// Created by Todd Fiala on 8/30/16. +// +// + +#include "DarwinProcessLauncher.h" + +// C includes +#include <spawn.h> +#include <sys/ptrace.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#ifndef _POSIX_SPAWN_DISABLE_ASLR +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#endif + +// LLDB includes +#include "lldb/lldb-enumerations.h" + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/PseudoTerminal.h" + +#include "CFBundle.h" +#include "CFString.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_darwin; +using namespace lldb_private::darwin_process_launcher; + +namespace { +static LaunchFlavor g_launch_flavor = LaunchFlavor::Default; +} + +namespace lldb_private { +namespace darwin_process_launcher { + +static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) { + int mib[CTL_MAXNAME] = { + 0, + }; + size_t len = CTL_MAXNAME; + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) + return 0; + + mib[len] = pid; + len++; + + cpu_type_t cpu; + size_t cpu_len = sizeof(cpu); + if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) + cpu = 0; + return cpu; +} + +static bool ResolveExecutablePath(const char *path, char *resolved_path, + size_t resolved_path_size) { + if (path == NULL || path[0] == '\0') + return false; + + char max_path[PATH_MAX]; + std::string result; + CFString::GlobPath(path, result); + + if (result.empty()) + result = path; + + struct stat path_stat; + if (::stat(path, &path_stat) == 0) { + if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { + CFBundle bundle(path); + CFReleaser<CFURLRef> url(bundle.CopyExecutableURL()); + if (url.get()) { + if (::CFURLGetFileSystemRepresentation( + url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) + return true; + } + } + } + + if (realpath(path, max_path)) { + // Found the path relatively... + ::strncpy(resolved_path, max_path, resolved_path_size); + return strlen(resolved_path) + 1 < resolved_path_size; + } else { + // Not a relative path, check the PATH environment variable if the + const char *PATH = getenv("PATH"); + if (PATH) { + const char *curr_path_start = PATH; + const char *curr_path_end; + while (curr_path_start && *curr_path_start) { + curr_path_end = strchr(curr_path_start, ':'); + if (curr_path_end == NULL) { + result.assign(curr_path_start); + curr_path_start = NULL; + } else if (curr_path_end > curr_path_start) { + size_t len = curr_path_end - curr_path_start; + result.assign(curr_path_start, len); + curr_path_start += len + 1; + } else + break; + + result += '/'; + result += path; + struct stat s; + if (stat(result.c_str(), &s) == 0) { + ::strncpy(resolved_path, result.c_str(), resolved_path_size); + return result.size() + 1 < resolved_path_size; + } + } + } + } + return false; +} + +// TODO check if we have a general purpose fork and exec. We may be +// able to get rid of this entirely. +static 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(); + } + } + return error; +} + +static 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; + } + break; + } + + case FileAction::eFileActionClose: { + const int error_code = + ::posix_spawn_file_actions_addclose(file_actions, action.GetFD()); + if (error_code != 0) { + error.SetError(error_code, eErrorTypePOSIX); + return error; + } + break; + } + + case FileAction::eFileActionDuplicate: { + const int error_code = ::posix_spawn_file_actions_adddup2( + file_actions, action.GetFD(), action.GetActionArgument()); + if (error_code != 0) { + error.SetError(error_code, eErrorTypePOSIX); + return error; + } + break; + } + + case FileAction::eFileActionNone: + default: + if (log) + log->Printf("%s(): unsupported file action %u", __FUNCTION__, + action.GetAction()); + break; + } + + 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; + } + + 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; + } + +#if !defined(__arm__) + + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType(); + if (desired_cpu_type != LLDB_INVALID_CPUTYPE) { + size_t ocount = 0; + error_code = + ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount); + if (error_code != 0) { + 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 + + 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; + } + + // 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) + log->Printf("%s(): cpu type for launched process pid=%i: " + "cpu_type=0x%8.8x", + __FUNCTION__, *pid, *actual_cpu_type); + } + + 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; + } + + if (log) { + StreamString stream; + stream.Printf("NativeProcessDarwin::%s(): launching with the " + "following launch info:", + __FUNCTION__); + launch_info.Dump(stream, nullptr); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + + // Retrieve the binary name given to us. + char given_path[PATH_MAX]; + given_path[0] = '\0'; + launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path)); + + // Determine the manner in which we'll launch. + *launch_flavor = g_launch_flavor; + if (*launch_flavor == LaunchFlavor::Default) { + // Our default launch method is posix spawn + *launch_flavor = LaunchFlavor::PosixSpawn; +#if defined WITH_FBS + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorFBS; + } +#elif defined WITH_BKS + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorBKS; + } +#elif defined WITH_SPRINGBOARD + // Check if we have an app bundle, if so launch using SpringBoard. + if (strstr(given_path, ".app")) { + *launch_flavor = eLaunchFlavorSpringBoard; + } +#endif + } + + // Attempt to resolve the binary name to an absolute path. + char resolved_path[PATH_MAX]; + resolved_path[0] = '\0'; + + 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); + } + + char launch_err_str[PATH_MAX]; + launch_err_str[0] = '\0'; + + // TODO figure out how to handle QSetProcessEvent + // const char *process_event = ctx.GetProcessEvent(); + + // Ensure the binary is there. + struct stat path_stat; + if (::stat(resolved_path, &path_stat) == -1) { + error.SetErrorToErrno(); + return error; + } + + // Fork a child process for debugging + // state_callback(eStateLaunching); + + const auto argv = launch_info.GetArguments().GetConstArgumentVector(); + const auto envp = + launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + + switch (*launch_flavor) { + case LaunchFlavor::ForkExec: { + ::pid_t pid = LLDB_INVALID_PROCESS_ID; + error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid, + pty_master_fd); + if (error.Success()) { + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); + } else { + // Reset any variables that might have been set during a failed + // launch attempt. + if (pty_master_fd) + *pty_master_fd = -1; + + // We're done. + return error; + } + } break; + +#ifdef WITH_FBS + case LaunchFlavor::FBS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingFBS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a FBS launch, but didn't succeed lets get out + } + } break; +#endif + +#ifdef WITH_BKS + case LaunchFlavor::BKS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingBKS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a BKS launch, but didn't succeed lets get out + } + } break; +#endif + +#ifdef WITH_SPRINGBOARD + case LaunchFlavor::SpringBoard: { + // .../whatever.app/whatever ? + // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in + // "com.apple.whatever" here + const char *app_ext = strstr(path, ".app/"); + if (app_ext == NULL) { + // .../whatever.app ? + int len = strlen(path); + if (len > 5) { + if (strcmp(path + len - 4, ".app") == 0) { + app_ext = path + len - 4; + } + } + } + if (app_ext) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, + disable_aslr, launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a springboard launch, but didn't succeed lets get out + } + } break; +#endif + + case LaunchFlavor::PosixSpawn: { + ::pid_t pid = LLDB_INVALID_PROCESS_ID; + + // Retrieve paths for stdin/stdout/stderr. + cpu_type_t actual_cpu_type = 0; + error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid, + &actual_cpu_type); + if (error.Success()) { + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid)); + if (pty_master_fd) + *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); + } else { + // Reset any variables that might have been set during a failed + // launch attempt. + if (pty_master_fd) + *pty_master_fd = -1; + + // We're done. + return error; + } + break; + } + + default: + // Invalid launch flavor. + error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown " + "launch flavor %d", + __FUNCTION__, (int)*launch_flavor); + return error; + } + + if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) { + // If we don't have a valid process ID and no one has set the error, + // then return a generic error. + if (error.Success()) + error.SetErrorStringWithFormat("%s(): failed to launch, no reason " + "specified", + __FUNCTION__); + } + + // We're done with the launch side of the operation. + return error; +} +} +} // namespaces diff --git a/source/Plugins/Process/Darwin/DarwinProcessLauncher.h b/source/Plugins/Process/Darwin/DarwinProcessLauncher.h new file mode 100644 index 000000000000..d1af4d09f8b7 --- /dev/null +++ b/source/Plugins/Process/Darwin/DarwinProcessLauncher.h @@ -0,0 +1,48 @@ +//===-- DarwinProcessLauncher.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef DarwinProcessLauncher_h +#define DarwinProcessLauncher_h + +// C headers +#include <mach/machine.h> +#include <sys/types.h> + +// C++ headers +#include <functional> + +// LLDB headers +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" + +#include "LaunchFlavor.h" + +namespace lldb_private { +namespace darwin_process_launcher { +// ============================================================================= +/// Launches a process for debugging. +/// +/// @param[inout] launch_info +/// Specifies details about the process to launch (e.g. path, architecture, +/// etc.). On output, includes the launched ProcessID (pid). +/// +/// @param[out] pty_master_fd +/// Returns the master side of the pseudo-terminal used to communicate +/// with stdin/stdout from the launched process. May be nullptr. +/// +/// @param[out] launch_flavor +/// Contains the launch flavor used when launching the process. +// ============================================================================= +Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd, + lldb_private::process_darwin::LaunchFlavor *launch_flavor); + +} // darwin_process_launcher +} // lldb_private + +#endif /* DarwinProcessLauncher_h */ diff --git a/source/Plugins/Process/Darwin/LaunchFlavor.h b/source/Plugins/Process/Darwin/LaunchFlavor.h new file mode 100644 index 000000000000..7b161712cffd --- /dev/null +++ b/source/Plugins/Process/Darwin/LaunchFlavor.h @@ -0,0 +1,33 @@ +//===-- LaunchFlavor.h ---------------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LaunchFlavor_h +#define LaunchFlavor_h + +namespace lldb_private { +namespace process_darwin { + +enum class LaunchFlavor { + Default = 0, + PosixSpawn = 1, + ForkExec = 2, +#ifdef WITH_SPRINGBOARD + SpringBoard = 3, +#endif +#ifdef WITH_BKS + BKS = 4, +#endif +#ifdef WITH_FBS + FBS = 5 +#endif +}; +} +} // namespaces + +#endif /* LaunchFlavor_h */ diff --git a/source/Plugins/Process/Darwin/MachException.cpp b/source/Plugins/Process/Darwin/MachException.cpp new file mode 100644 index 000000000000..81706441494a --- /dev/null +++ b/source/Plugins/Process/Darwin/MachException.cpp @@ -0,0 +1,543 @@ +//===-- MachException.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/18/07. +// +//===----------------------------------------------------------------------===// + +#include "MachException.h" + +// C includes +#include <errno.h> +#include <sys/ptrace.h> +#include <sys/types.h> + +// C++ includes +#include <mutex> + +// LLDB includes +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBAssert.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_darwin; + +// Routine mach_exception_raise +extern "C" kern_return_t +catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, + mach_port_t task, exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt); + +extern "C" kern_return_t catch_mach_exception_raise_state( + mach_port_t exception_port, exception_type_t exception, + const mach_exception_data_t code, mach_msg_type_number_t codeCnt, + int *flavor, const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt); + +// Routine mach_exception_raise_state_identity +extern "C" kern_return_t catch_mach_exception_raise_state_identity( + mach_port_t exception_port, mach_port_t thread, mach_port_t task, + exception_type_t exception, mach_exception_data_t code, + mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt); + +extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +// Any access to the g_message variable should be done by locking the +// g_message_mutex first, using the g_message variable, then unlocking +// the g_message_mutex. See MachException::Message::CatchExceptionRaise() +// for sample code. + +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_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; +} + +#if 0 +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); + stream.Flush(); +} +#endif + +bool MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info, + const UnixSignals &signals, + Stream &stream) const { + if (!stop_info) + return false; + + // Zero out the structure. + memset(stop_info, 0, sizeof(struct ThreadStopInfo)); + + if (exc_type == 0) { + stop_info->reason = eStopReasonInvalid; + return true; + } + + // We always stop with a mach exception. + stop_info->reason = eStopReasonException; + // Save the EXC_XXXX exception type. + stop_info->details.exception.type = exc_type; + + // Fill in a text description + const char *exc_name = MachException::Name(exc_type); + if (exc_name) + stream.Printf("%s", exc_name); + else + stream.Printf("%i", exc_type); + + stop_info->details.exception.data_count = exc_data.size(); + + int soft_signal = SoftSignal(); + if (soft_signal) { + const char *sig_str = signals.GetSignalAsCString(soft_signal); + stream.Printf(" EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, + sig_str ? sig_str : "unknown signal"); + } else { + // No special disassembly for exception data, just print it. + size_t idx; + stream.Printf(" data[%llu] = {", + (uint64_t)stop_info->details.exception.data_count); + + for (idx = 0; idx < stop_info->details.exception.data_count; ++idx) { + stream.Printf( + "0x%llx%c", (uint64_t)exc_data[idx], + ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); + } + } + + // Copy the exception data + for (size_t i = 0; i < stop_info->details.exception.data_count; i++) + stop_info->details.exception.data[i] = exc_data[i]; + + return true; +} + +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; +} + +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; +} + +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); + + 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); + + // 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; +} + +#define PREV_EXC_MASK_ALL \ + (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \ + EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \ + EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \ + EXC_MASK_MACHINE) + +// Don't listen for EXC_RESOURCE, it should really get handled by the system +// handler. + +#ifndef EXC_RESOURCE +#define EXC_RESOURCE 11 +#endif + +#ifndef EXC_MASK_RESOURCE +#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE) +#endif + +#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) + +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); + + // Be careful to be able to have debugserver built on a newer OS than what + // it is currently running on by being able to start with all exceptions + // and back off to just what is supported on the current system + mask = LLDB_EXC_MASK; + + count = (sizeof(ports) / sizeof(ports[0])); + auto mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, + behaviors, flavors); + if (mach_err) + error.SetError(mach_err, eErrorTypeMachKernel); + + if (log) { + if (error.Success()) { + 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; + } + return error; +} + +Error MachException::PortInfo::Restore(task_t task) { + Error error; + + 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; + } + } + + count = 0; + return error; +} + +const char *MachException::Name(exception_type_t exc_type) { + switch (exc_type) { + case EXC_BAD_ACCESS: + return "EXC_BAD_ACCESS"; + case EXC_BAD_INSTRUCTION: + return "EXC_BAD_INSTRUCTION"; + case EXC_ARITHMETIC: + return "EXC_ARITHMETIC"; + case EXC_EMULATION: + return "EXC_EMULATION"; + case EXC_SOFTWARE: + return "EXC_SOFTWARE"; + case EXC_BREAKPOINT: + return "EXC_BREAKPOINT"; + case EXC_SYSCALL: + return "EXC_SYSCALL"; + case EXC_MACH_SYSCALL: + return "EXC_MACH_SYSCALL"; + case EXC_RPC_ALERT: + return "EXC_RPC_ALERT"; +#ifdef EXC_CRASH + case EXC_CRASH: + return "EXC_CRASH"; +#endif + default: + break; + } + return NULL; +} diff --git a/source/Plugins/Process/Darwin/MachException.h b/source/Plugins/Process/Darwin/MachException.h new file mode 100644 index 000000000000..ac8cd7030c55 --- /dev/null +++ b/source/Plugins/Process/Darwin/MachException.h @@ -0,0 +1,140 @@ +//===-- MachException.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/18/07. +// +//===----------------------------------------------------------------------===// + +#ifndef __MachException_h__ +#define __MachException_h__ + +#include <mach/mach.h> +#include <vector> + +#include "lldb/Host/Debug.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { +namespace process_darwin { + +typedef union MachMessageTag { + mach_msg_header_t hdr; + char data[1024]; +} MachMessage; + +class MachException { +public: + struct PortInfo { + exception_mask_t mask; // the exception mask for this device which may be a + // subset of EXC_MASK_ALL... + exception_mask_t masks[EXC_TYPES_COUNT]; + mach_port_t ports[EXC_TYPES_COUNT]; + exception_behavior_t behaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t flavors[EXC_TYPES_COUNT]; + mach_msg_type_number_t count; + + 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 +} // namespace lldb_private + +#endif diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp new file mode 100644 index 000000000000..e56375ebaa49 --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp @@ -0,0 +1,1576 @@ +//===-- NativeProcessDarwin.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeProcessDarwin.h" + +// C includes +#include <mach/mach_init.h> +#include <mach/mach_traps.h> +#include <sys/ptrace.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +// C++ includes +// LLDB includes +#include "lldb/Core/Log.h" +#include "lldb/Core/State.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/PseudoTerminal.h" + +#include "CFBundle.h" +#include "CFString.h" +#include "DarwinProcessLauncher.h" + +#include "MachException.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_darwin; +using namespace lldb_private::darwin_process_launcher; + +// ----------------------------------------------------------------------------- +// Hidden Impl +// ----------------------------------------------------------------------------- + +namespace { +struct hack_task_dyld_info { + mach_vm_address_t all_image_info_addr; + mach_vm_size_t all_image_info_size; +}; +} + +// ----------------------------------------------------------------------------- +// Public Static Methods +// ----------------------------------------------------------------------------- + +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; + + 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; + } + + // Return the process and process id to the caller through the launch args. + native_process_sp = np_darwin_sp; + 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)); + 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; + + // TODO get attach to return this value. + const int pty_master_fd = -1; + std::shared_ptr<NativeProcessDarwin> native_process_darwin_sp( + new NativeProcessDarwin(pid, pty_master_fd)); + + if (!native_process_darwin_sp->RegisterNativeDelegate(native_delegate)) { + error.SetErrorStringWithFormat("failed to register the native " + "delegate"); + return error; + } + + native_process_darwin_sp->AttachToInferior(mainloop, pid, error); + if (!error.Success()) + return error; + + native_process_sp = native_process_darwin_sp; + return error; +} + +// ----------------------------------------------------------------------------- +// ctor/dtor +// ----------------------------------------------------------------------------- + +NativeProcessDarwin::NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd) + : NativeProcessProtocol(pid), m_task(TASK_NULL), m_did_exec(false), + m_cpu_type(0), m_exception_port(MACH_PORT_NULL), m_exc_port_info(), + m_exception_thread(nullptr), m_exception_messages_mutex(), + m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_thread_list(), + m_thread_actions(), m_waitpid_pipe(), m_waitpid_thread(nullptr), + m_waitpid_reader_handle() { + // TODO add this to the NativeProcessProtocol constructor. + m_terminal_fd = pty_master_fd; +} + +NativeProcessDarwin::~NativeProcessDarwin() {} + +// ----------------------------------------------------------------------------- +// Instance methods +// ----------------------------------------------------------------------------- + +Error NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor, + MainLoop &main_loop) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + +#if 0 + m_path = path; + size_t i; + char const *arg; + for (i=0; (arg = argv[i]) != NULL; i++) + 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()); + + // Terminate the inferior process. There's nothing meaningful we can + // do if we can't receive signals and exceptions. Since we launched + // the process, it's fair game for us to kill it. + ::ptrace(PT_KILL, m_pid, 0, 0); + SetState(eStateExited); + + return error; + } + + StartSTDIOThread(); + + if (launch_flavor == LaunchFlavor::PosixSpawn) { + SetState(eStateAttaching); + errno = 0; + int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + if (err == 0) { + // m_flags |= eMachProcessFlagsAttached; + 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(): 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; + } + + // Indicate that we're stopped, as we always launch suspended. + SetState(eStateStopped); + + // Success. + return error; +} + +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::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::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(); +} + +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("::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) + +#ifdef WITH_BKS + CFReleaser<BKSWatchdogAssertionRef> watchdog; + if (process->ProcessUsingBackBoard()) { + ::pid_t pid = process->GetID(); + CFAllocatorRef alloc = kCFAllocatorDefault; + watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); + } +#endif // #ifdef WITH_BKS + + // Do we want to use a weak pointer to the NativeProcessDarwin here, in + // which case we can guarantee we don't whack the process monitor if we + // race between this thread and the main one on shutdown? + while (IsExceptionPortValid()) { + ::pthread_testcancel(); + + MachException::Message exception_message; + + if (num_exceptions_received > 0) { + // We don't want a timeout here, just receive as many exceptions as + // we can since we already have one. We want to get all currently + // available exceptions for this task at once. + error = exception_message.Receive( + GetExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); + } else if (periodic_timeout > 0) { + // We need to stop periodically in this loop, so try and get a mach + // message with a valid timeout (ms). + error = exception_message.Receive(GetExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT | + MACH_RCV_TIMEOUT, + periodic_timeout); + } else { + // We don't need to parse all current exceptions or stop + // periodically, just wait for an exception forever. + error = exception_message.Receive(GetExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); + } + + if (error.Success()) { + // We successfully received an exception. + if (exception_message.CatchExceptionRaise(task)) { + ++num_exceptions_received; + ExceptionMessageReceived(exception_message); + } + } else { + if (error.GetError() == MACH_RCV_INTERRUPTED) { + // We were interrupted. + + // If we have no task port we should exit this thread, as it implies + // the inferior went down. + if (!IsExceptionPortValid()) { + 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()); + } +#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); + + // Ensure the inferior task is valid. + if (!IsTaskValid()) { + error.SetErrorStringWithFormat("cannot start exception thread: " + "task 0x%4.4x is not valid", + m_task); + return error; + } + + // Get the mach port for the process monitor. + mach_port_t task_self = mach_task_self(); + + // Allocate an exception port that we will use to track our child process + auto mach_err = ::mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, + &m_exception_port); + error.SetError(mach_err, eErrorTypeMachKernel); + if (error.Fail()) { + 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; + } + + // 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; + } + + // 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()); + } + + 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; + + auto mach_err = + ::task_info(m_task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); + error.SetError(mach_err, eErrorTypeMachKernel); + if (error.Success()) { + // We now have the address of the all image infos structure. + return dyld_info.all_image_info_addr; + } + + // We don't have it. + return LLDB_INVALID_ADDRESS; +} + +uint32_t NativeProcessDarwin::GetCPUTypeForLocalProcess(::pid_t pid) { + int mib[CTL_MAXNAME] = { + 0, + }; + size_t len = CTL_MAXNAME; + + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) + return 0; + + mib[len] = pid; + len++; + + cpu_type_t cpu; + size_t cpu_len = sizeof(cpu); + if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) + cpu = 0; + return cpu; +} + +uint32_t NativeProcessDarwin::GetCPUType() const { + if (m_cpu_type == 0 && m_pid != 0) + m_cpu_type = GetCPUTypeForLocalProcess(m_pid); + return m_cpu_type; +} + +task_t NativeProcessDarwin::ExceptionMessageBundleComplete() { + // We have a complete bundle of exceptions for our child process. + 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; + + // 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(); + + // 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); + } + } + } + + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + m_thread_list.ProcessDidStop(*this); + + // Let each thread know of any exceptions + for (i = 0; i < m_exception_messages.size(); ++i) { + // Let the thread list forward all exceptions on down to each thread. + if (m_exception_messages[i].state.task_port == task) { + // This exception is for our inferior. + m_thread_list.NotifyException(m_exception_messages[i].state); + } + + if (log) { + StreamString stream; + m_exception_messages[i].Dump(stream); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + } + + if (log) { + StreamString stream; + m_thread_list.Dump(stream); + stream.Flush(); + log->PutCString(stream.GetString().c_str()); + } + + bool step_more = false; + if (m_thread_list.ShouldStop(step_more) && (auto_resume == false)) { +// TODO - need to hook up event system here. !!!! +#if 0 + // Wait for the eEventProcessRunningStateChanged event to be reset + // before changing state to stopped to avoid race condition with + // very fast start/stops. + struct timespec timeout; + + //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms + DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms + m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, + &timeout); +#endif + SetState(eStateStopped); + } else { + // Resume without checking our current state. + PrivateResume(); + } + + return m_task; +} + +void NativeProcessDarwin::StartSTDIOThread() { + // TODO implement +} + +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; + } + + return reinterpret_cast<NativeProcessDarwin *>(arg)->DoWaitpidThread(); +} + +void NativeProcessDarwin::MaybeRaiseThreadPriority() { +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } +#endif +} + +void *NativeProcessDarwin::DoWaitpidThread() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (m_pid == LLDB_INVALID_PROCESS_ID) { + 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; + + 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 (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::SendInferiorExitStatusToMainLoop(::pid_t pid, + int status) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + size_t bytes_written = 0; + + // Send the pid. + error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written); + if (error.Fail() || (bytes_written < sizeof(pid))) { + 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; + } + + // 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() - failed to write " + "waitpid exit result to the pipe. Client will not " + "hear about inferior exit status!", + __FUNCTION__); + } + return error; +} + +Error NativeProcessDarwin::HandleWaitpidResult() { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Read the pid. + const bool notify_status = true; + + ::pid_t pid = -1; + size_t bytes_read = 0; + error = m_waitpid_pipe.Read(&pid, sizeof(pid), bytes_read); + if (error.Fail() || (bytes_read < sizeof(pid))) { + 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; + } + + // 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; + } + + 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()); + } + } + + // Sleep a bit and try again + ::usleep(usec_interval); + } + + // We failed to get the task for the inferior process. + // Ensure that it is cleared out. + m_task = TASK_NULL; + } + return m_task; +} + +void NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, + Error &error) { + error.SetErrorString("TODO: implement"); +} + +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); + } + + 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)); + + 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; + } + + 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; + + const tid_t tid = + m_thread_list.GetThreadIDByMachPortNumber(message.state.thread_port); + const ResumeAction *action = nullptr; + if (tid != LLDB_INVALID_THREAD_ID) + action = m_thread_actions.GetActionForThread(tid, false); + + if (action) { + thread_reply_signal = action->signal; + if (thread_reply_signal) + m_thread_actions.SetSignalHandledForThread(tid); + } + + error = message.Reply(m_pid, m_task, thread_reply_signal); + if (error.Fail() && log) { + // We log any error here, but we don't stop the exception + // response handling. + 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; +} + +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; + } + + 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); + } + + return error; +} + +bool NativeProcessDarwin::IsTaskValid() const { + if (m_task == TASK_NULL) + return false; + + struct task_basic_info task_info; + return GetTaskBasicInfo(m_task, &task_info).Success(); +} + +bool NativeProcessDarwin::IsTaskValid(task_t task) const { + if (task == TASK_NULL) + return false; + + struct task_basic_info task_info; + return GetTaskBasicInfo(task, &task_info).Success(); +} + +mach_port_t NativeProcessDarwin::GetExceptionPort() const { + return m_exception_port; +} + +bool NativeProcessDarwin::IsExceptionPortValid() const { + return MACH_PORT_VALID(m_exception_port); +} + +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; + } + + 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); + + return error; +} + +Error NativeProcessDarwin::Resume(const ResumeActionList &resume_actions) { + Error error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (log) + log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__); + + if (CanResume()) { + m_thread_actions = resume_actions; + error = PrivateResume(); + return error; + } + + auto state = GetState(); + if (state == eStateRunning) { + if (log) + log->Printf("NativeProcessDarwin::%s(): task 0x%x is already " + "running, ignoring...", + __FUNCTION__, TaskPortForProcessID(error)); + return error; + } + + // We can't resume from this state. + error.SetErrorStringWithFormat("task 0x%x has state %s, can't resume", + TaskPortForProcessID(error), + StateAsCString(state)); + return error; +} + +Error NativeProcessDarwin::Halt() { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +Error NativeProcessDarwin::Detach() { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +Error NativeProcessDarwin::Signal(int signo) { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +Error NativeProcessDarwin::Interrupt() { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +Error NativeProcessDarwin::Kill() { + 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::ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) { + 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::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::AllocateMemory(size_t size, uint32_t permissions, + lldb::addr_t &addr) { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +Error NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr) { + Error error; + error.SetErrorString("TODO: implement"); + return error; +} + +lldb::addr_t NativeProcessDarwin::GetSharedLibraryInfoAddress() { + return LLDB_INVALID_ADDRESS; +} + +size_t NativeProcessDarwin::UpdateThreads() { return 0; } + +bool NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const { + return false; +} + +Error NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + 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; +} + +// ----------------------------------------------------------------- +// 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; +} diff --git a/source/Plugins/Process/Darwin/NativeProcessDarwin.h b/source/Plugins/Process/Darwin/NativeProcessDarwin.h new file mode 100644 index 000000000000..69c1b8d9e4cc --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeProcessDarwin.h @@ -0,0 +1,384 @@ +//===-- NativeProcessDarwin.h --------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef NativeProcessDarwin_h +#define NativeProcessDarwin_h + +// NOTE: this code should only be compiled on Apple Darwin systems. It is +// not cross-platform code and is not intended to build on any other platform. +// Therefore, platform-specific headers and code are okay here. + +// C includes +#include <mach/mach_types.h> + +// C++ includes +#include <mutex> +#include <unordered_set> + +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.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 "LaunchFlavor.h" +#include "MachException.h" +#include "NativeThreadDarwin.h" +#include "NativeThreadListDarwin.h" + +namespace lldb_private { +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; + + 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 SupportHardwareSingleStepping() const; + +protected: + // ----------------------------------------------------------------- + // NativeProcessProtocol protected interface + // ----------------------------------------------------------------- + Error + GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, + size_t &actual_opcode_size, + const uint8_t *&trap_opcode_bytes) override; + +private: + // ----------------------------------------------------------------- + /// Mach task-related Member Variables + // ----------------------------------------------------------------- + + // The task port for the inferior process. + mutable task_t m_task; + + // True if the inferior process did an exec since we started + // monitoring it. + bool m_did_exec; + + // The CPU type of this process. + mutable cpu_type_t m_cpu_type; + + // ----------------------------------------------------------------- + /// Exception/Signal Handling Member Variables + // ----------------------------------------------------------------- + + // Exception port on which we will receive child exceptions + mach_port_t m_exception_port; + + // Saved state of the child exception port prior to us installing + // our own intercepting port. + MachException::PortInfo m_exc_port_info; + + // The thread that runs the Mach exception read and reply handler. + pthread_t m_exception_thread; + + // TODO see if we can remove this if we get the exception collection + // and distribution to happen in a single-threaded fashion. + std::recursive_mutex m_exception_messages_mutex; + + // A collection of exception messages caught when listening to the + // exception port. + MachException::Message::collection m_exception_messages; + + // When we call MachProcess::Interrupt(), we want to send this + // signal (if non-zero). + int m_sent_interrupt_signo; + + // If we resume the process and still haven't received our + // interrupt signal (if this is non-zero). + int m_auto_resume_signo; + + // ----------------------------------------------------------------- + /// Thread-related Member Variables + // ----------------------------------------------------------------- + NativeThreadListDarwin m_thread_list; + ResumeActionList m_thread_actions; + + // ----------------------------------------------------------------- + /// Process Lifetime Member Variable + // ----------------------------------------------------------------- + + // The pipe over which the waitpid thread and the main loop will + // communicate. + Pipe m_waitpid_pipe; + + // The thread that runs the waitpid handler. + pthread_t m_waitpid_thread; + + // waitpid reader callback handle. + MainLoop::ReadHandleUP m_waitpid_reader_handle; + +#if 0 + ArchSpec m_arch; + + LazyBool m_supports_mem_region; + std::vector<MemoryRegionInfo> m_mem_region_cache; + + lldb::tid_t m_pending_notification_tid; + + // List of thread ids stepping with a breakpoint with the address of + // the relevan breakpoint + std::map<lldb::tid_t, lldb::addr_t> + m_threads_stepping_with_breakpoint; +#endif + + // ----------------------------------------------------------------- + // 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); + + Error SaveExceptionPortInfo(); + + void ExceptionMessageReceived(const MachException::Message &message); + + void MaybeRaiseThreadPriority(); + + Error StartExceptionThread(); + + Error SendInferiorExitStatusToMainLoop(::pid_t pid, int status); + + Error HandleWaitpidResult(); + + bool ProcessUsingSpringBoard() const; + + bool ProcessUsingBackBoard() const; + + static void *ExceptionThread(void *arg); + + void *DoExceptionThread(); + + lldb::addr_t GetDYLDAllImageInfosAddress(Error &error) const; + + static uint32_t GetCPUTypeForLocalProcess(::pid_t pid); + + uint32_t GetCPUType() const; + + task_t ExceptionMessageBundleComplete(); + + void StartSTDIOThread(); + + Error StartWaitpidThread(MainLoop &main_loop); + + static void *WaitpidThread(void *arg); + + void *DoWaitpidThread(); + + 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); + + ::pid_t Attach(lldb::pid_t pid, Error &error); + + Error PrivateResume(); + + Error ReplyToAllExceptions(); + + Error ResumeTask(); + + bool IsTaskValid() const; + + bool IsTaskValid(task_t task) const; + + mach_port_t GetExceptionPort() const; + + bool IsExceptionPortValid() const; + + Error GetTaskBasicInfo(task_t task, struct task_basic_info *info) const; + + Error SuspendTask(); + + static Error SetDefaultPtraceOpts(const lldb::pid_t); + + static void *MonitorThread(void *baton); + + void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status); + + void WaitForNewThread(::pid_t tid); + + void MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin &thread); + + void MonitorTrace(NativeThreadDarwin &thread); + + void MonitorBreakpoint(NativeThreadDarwin &thread); + + void MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t wp_index); + + void MonitorSignal(const siginfo_t &info, NativeThreadDarwin &thread, + bool exited); + + Error SetupSoftwareSingleStepping(NativeThreadDarwin &thread); + +#if 0 + static ::ProcessMessage::CrashReason + GetCrashReasonForSIGSEGV(const siginfo_t *info); + + static ::ProcessMessage::CrashReason + GetCrashReasonForSIGILL(const siginfo_t *info); + + static ::ProcessMessage::CrashReason + GetCrashReasonForSIGFPE(const siginfo_t *info); + + static ::ProcessMessage::CrashReason + 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 +} // namespace lldb_private + +#endif /* NativeProcessDarwin_h */ diff --git a/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp b/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp new file mode 100644 index 000000000000..5e7f9ae7e6f9 --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp @@ -0,0 +1,284 @@ +//===-- NativeThreadDarwin.cpp -------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeThreadDarwin.h" + +// C includes +#include <libproc.h> + +// LLDB includes +#include "lldb/Core/Stream.h" + +#include "NativeProcessDarwin.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_darwin; + +uint64_t NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( + ::thread_t mach_port_id) { + thread_identifier_info_data_t tident; + mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; + + auto mach_err = ::thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, + (thread_info_t)&tident, &tident_count); + if (mach_err != KERN_SUCCESS) { + // When we fail to get thread info for the supposed port, assume it is + // really a globally unique thread id already, or return the best thing + // we can, which is the thread port. + return mach_port_id; + } + return tident.thread_id; +} + +NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process, + bool is_64_bit, + lldb::tid_t unique_thread_id, + ::thread_t mach_thread_port) + : NativeThreadProtocol(process, unique_thread_id), + m_mach_thread_port(mach_thread_port), m_basic_info(), + m_proc_threadinfo() {} + +bool NativeThreadDarwin::GetIdentifierInfo() { + // Don't try to get the thread info once and cache it for the life of the + // thread. It changes over time, for instance + // if the thread name changes, then the thread_handle also changes... So you + // have to refetch it every time. + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t kret = ::thread_info(m_mach_thread_port, THREAD_IDENTIFIER_INFO, + (thread_info_t)&m_ident_info, &count); + return kret == KERN_SUCCESS; + + return false; +} + +std::string NativeThreadDarwin::GetName() { + std::string name; + + if (GetIdentifierInfo()) { + auto process_sp = GetProcess(); + if (!process_sp) { + name = "<unavailable>"; + return name; + } + + int len = ::proc_pidinfo(process_sp->GetID(), PROC_PIDTHREADINFO, + m_ident_info.thread_handle, &m_proc_threadinfo, + sizeof(m_proc_threadinfo)); + + if (len && m_proc_threadinfo.pth_name[0]) + name = m_proc_threadinfo.pth_name; + } + return name; +} + +lldb::StateType NativeThreadDarwin::GetState() { + // TODO implement + return eStateInvalid; +} + +bool NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + // TODO implement + return false; +} + +NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() { + // TODO implement + return NativeRegisterContextSP(); +} + +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; +} + +void NativeThreadDarwin::Dump(Stream &stream) const { +// This is what we really want once we have the thread class wired up. +#if 0 + DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", + index, + m_seq_id, + m_unique_id, + GetPC(INVALID_NUB_ADDRESS), + GetSP(INVALID_NUB_ADDRESS), + m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, + m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, + m_basic_info.cpu_usage, + m_basic_info.policy, + m_basic_info.run_state, + thread_run_state, + m_basic_info.flags, + m_basic_info.suspend_count, m_suspend_count, + m_basic_info.sleep_time); + +#else + // Here's all we have right now. + stream.Printf("tid: 0x%8.8" PRIx64 ", thread port: 0x%4.4x", GetID(), + m_mach_thread_port); +#endif +} + +bool NativeThreadDarwin::NotifyException(MachException::Data &exc) { +// TODO implement this. +#if 0 + // Allow the arch specific protocol to process (MachException::Data &)exc + // first before possible reassignment of m_stop_exception with exc. + // See also MachThread::GetStopException(). + bool handled = m_arch_ap->NotifyException(exc); + + if (m_stop_exception.IsValid()) + { + // We may have more than one exception for a thread, but we need to + // only remember the one that we will say is the reason we stopped. + // We may have been single stepping and also gotten a signal exception, + // so just remember the most pertinent one. + if (m_stop_exception.IsBreakpoint()) + m_stop_exception = exc; + } + else + { + m_stop_exception = exc; + } + + return handled; +#else + // Pretend we handled it. + return true; +#endif +} + +bool NativeThreadDarwin::ShouldStop(bool &step_more) const { +// TODO: implement this +#if 0 + // See if this thread is at a breakpoint? + DNBBreakpoint *bp = CurrentBreakpoint(); + + if (bp) + { + // This thread is sitting at a breakpoint, ask the breakpoint + // if we should be stopping here. + return true; + } + else + { + if (m_arch_ap->StepNotComplete()) + { + step_more = true; + return false; + } + // The thread state is used to let us know what the thread was + // trying to do. MachThread::ThreadWillResume() will set the + // thread state to various values depending if the thread was + // the current thread and if it was to be single stepped, or + // resumed. + if (GetState() == eStateRunning) + { + // If our state is running, then we should continue as we are in + // the process of stepping over a breakpoint. + return false; + } + else + { + // Stop if we have any kind of valid exception for this + // thread. + if (GetStopException().IsValid()) + return true; + } + } + return false; +#else + return false; +#endif +} + +void NativeThreadDarwin::ThreadDidStop() { +// TODO implement this. +#if 0 + // This thread has existed prior to resuming under debug nub control, + // and has just been stopped. Do any cleanup that needs to be done + // after running. + + // The thread state and breakpoint will still have the same values + // as they had prior to resuming the thread, so it makes it easy to check + // if we were trying to step a thread, or we tried to resume while being + // at a breakpoint. + + // When this method gets called, the process state is still in the + // state it was in while running so we can act accordingly. + m_arch_ap->ThreadDidStop(); + + + // We may have suspended this thread so the primary thread could step + // without worrying about race conditions, so lets restore our suspend + // count. + RestoreSuspendCountAfterStop(); + + // Update the basic information for a thread + MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); + + if (m_basic_info.suspend_count > 0) + SetState(eStateSuspended); + else + SetState(eStateStopped); +#endif +} + +bool NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread) { + return thread != (::thread_t)(0); +} + +const struct thread_basic_info *NativeThreadDarwin::GetBasicInfo() const { + if (GetBasicInfo(m_mach_thread_port, &m_basic_info)) + return &m_basic_info; + return NULL; +} + +bool NativeThreadDarwin::GetBasicInfo(::thread_t thread, + struct thread_basic_info *basicInfoPtr) { + if (MachPortNumberIsValid(thread)) { + unsigned int info_count = THREAD_BASIC_INFO_COUNT; + kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, + (thread_info_t)basicInfoPtr, &info_count); + if (err == KERN_SUCCESS) + return true; + } + ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); + return false; +} + +bool NativeThreadDarwin::IsUserReady() const { + if (m_basic_info.run_state == 0) + GetBasicInfo(); + + switch (m_basic_info.run_state) { + default: + case TH_STATE_UNINTERRUPTIBLE: + break; + + case TH_STATE_RUNNING: + case TH_STATE_STOPPED: + case TH_STATE_WAITING: + case TH_STATE_HALTED: + return true; + } + return false; +} + +NativeProcessDarwinSP NativeThreadDarwin::GetNativeProcessDarwinSP() { + return std::static_pointer_cast<NativeProcessDarwin>(GetProcess()); +} diff --git a/source/Plugins/Process/Darwin/NativeThreadDarwin.h b/source/Plugins/Process/Darwin/NativeThreadDarwin.h new file mode 100644 index 000000000000..b8d9089e673e --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeThreadDarwin.h @@ -0,0 +1,178 @@ +//===-- NativeThreadDarwin.h ---------------------------------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef NativeThreadDarwin_H +#define NativeThreadDarwin_H + +// C includes +#include <mach/mach_types.h> +#include <sched.h> +#include <sys/proc_info.h> + +// C++ includes +#include <map> +#include <memory> +#include <string> + +// LLDB includes +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/lldb-private-forward.h" + +#include "MachException.h" + +namespace lldb_private { +namespace process_darwin { + +class NativeProcessDarwin; +using NativeProcessDarwinSP = std::shared_ptr<NativeProcessDarwin>; + +class NativeThreadListDarwin; + +class NativeThreadDarwin : public NativeThreadProtocol { + friend class NativeProcessDarwin; + friend class NativeThreadListDarwin; + +public: + static uint64_t + GetGloballyUniqueThreadIDForMachPortID(::thread_t mach_port_id); + + NativeThreadDarwin(NativeProcessDarwin *process, bool is_64_bit, + lldb::tid_t unique_thread_id = 0, + ::thread_t mach_thread_port = 0); + + // ----------------------------------------------------------------- + // NativeThreadProtocol Interface + // ----------------------------------------------------------------- + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextSP GetRegisterContext() override; + + Error SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Error RemoveWatchpoint(lldb::addr_t addr) override; + + // ----------------------------------------------------------------- + // New methods that are fine for others to call. + // ----------------------------------------------------------------- + void Dump(Stream &stream) const; + +private: + // ----------------------------------------------------------------- + // Interface for friend classes + // ----------------------------------------------------------------- + + /// Resumes the thread. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + 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); + + bool NotifyException(MachException::Data &exc); + + bool ShouldStop(bool &step_more) const; + + void ThreadDidStop(); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + + /// Return true if the thread is stopped. + /// If stopped by a signal, indicate the signo in the signo + /// argument. Otherwise, return LLDB_INVALID_SIGNAL_NUMBER. + bool IsStopped(int *signo); + + const struct thread_basic_info *GetBasicInfo() const; + + static bool GetBasicInfo(::thread_t thread, + struct thread_basic_info *basicInfoPtr); + + bool IsUserReady() const; + + void SetStoppedByExec(); + + void SetStoppedByBreakpoint(); + + void SetStoppedByWatchpoint(uint32_t wp_index); + + bool IsStoppedAtBreakpoint(); + + bool IsStoppedAtWatchpoint(); + + void SetStoppedByTrace(); + + void SetStoppedWithNoReason(); + + void SetExited(); + + 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; } + + static bool MachPortNumberIsValid(::thread_t thread); + + // --------------------------------------------------------------------- + // Private interface + // --------------------------------------------------------------------- + bool GetIdentifierInfo(); + + void MaybeLogStateChange(lldb::StateType new_state); + + NativeProcessDarwinSP GetNativeProcessDarwinSP(); + + void SetStopped(); + + inline void MaybePrepareSingleStepWorkaround(); + + inline void MaybeCleanupSingleStepWorkaround(); + + // ----------------------------------------------------------------- + // Member Variables + // ----------------------------------------------------------------- + + // The mach thread port for the thread. + ::thread_t m_mach_thread_port; + + // The most recently-retrieved thread basic info. + mutable ::thread_basic_info m_basic_info; + + struct proc_threadinfo m_proc_threadinfo; + + thread_identifier_info_data_t m_ident_info; + +#if 0 + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + NativeRegisterContextSP m_reg_context_sp; + std::string m_stop_description; + using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; + WatchpointIndexMap m_watchpoint_index_map; + // cpu_set_t m_original_cpu_set; // For single-step workaround. +#endif +}; + +typedef std::shared_ptr<NativeThreadDarwin> NativeThreadDarwinSP; + +} // namespace process_darwin +} // namespace lldb_private + +#endif // #ifndef NativeThreadDarwin_H diff --git a/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp b/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp new file mode 100644 index 000000000000..aa9b04157658 --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp @@ -0,0 +1,698 @@ +//===-- NativeThreadListDarwin.cpp ------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/19/07. +// +//===----------------------------------------------------------------------===// + +#include "NativeThreadListDarwin.h" + +// C includes +#include <inttypes.h> +#include <mach/vm_map.h> +#include <sys/sysctl.h> + +// LLDB includes +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Stream.h" +#include "lldb/lldb-enumerations.h" + +#include "NativeProcessDarwin.h" +#include "NativeThreadDarwin.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_darwin; + +NativeThreadListDarwin::NativeThreadListDarwin() + : m_threads(), m_threads_mutex(), m_is_64_bit(false) {} + +NativeThreadListDarwin::~NativeThreadListDarwin() {} + +// These methods will be accessed directly from NativeThreadDarwin +#if 0 +nub_state_t +NativeThreadListDarwin::GetState(nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetState(); + return eStateInvalid; +} + +const char * +NativeThreadListDarwin::GetName (nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetName(); + return NULL; +} +#endif + +// TODO: figure out if we need to add this to NativeThreadDarwin yet. +#if 0 +ThreadInfo::QoS +NativeThreadListDarwin::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); + return ThreadInfo::QoS(); +} + +nub_addr_t +NativeThreadListDarwin::GetPThreadT (nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetPThreadT(); + return INVALID_NUB_ADDRESS; +} + +nub_addr_t +NativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetDispatchQueueT(); + return INVALID_NUB_ADDRESS; +} + +nub_addr_t +NativeThreadListDarwin::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); + return INVALID_NUB_ADDRESS; +} +#endif + +// TODO implement these +#if 0 +nub_thread_t +NativeThreadListDarwin::SetCurrentThread(nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + { + m_current_thread = thread_sp; + return tid; + } + return INVALID_NUB_THREAD; +} + + +bool +NativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetStopException().GetStopInfo(stop_info); + return false; +} + +bool +NativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) +{ + thread_t mach_port_number = GetMachPortNumberByThreadID (tid); + + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; +} + +void +NativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + thread_sp->GetStopException().DumpStopReason(); +} + +const char * +NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetBasicInfoAsString(); + return NULL; +} + +#endif + +NativeThreadDarwinSP +NativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + for (auto thread_sp : m_threads) { + if (thread_sp && (thread_sp->GetID() == tid)) + return thread_sp; + } + return NativeThreadDarwinSP(); +} + +NativeThreadDarwinSP NativeThreadListDarwin::GetThreadByMachPortNumber( + ::thread_t mach_port_number) const { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + for (auto thread_sp : m_threads) { + if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) + return thread_sp; + } + return NativeThreadDarwinSP(); +} + +lldb::tid_t NativeThreadListDarwin::GetThreadIDByMachPortNumber( + ::thread_t mach_port_number) const { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + for (auto thread_sp : m_threads) { + if (thread_sp && (thread_sp->GetMachPortNumber() == mach_port_number)) + return thread_sp->GetID(); + } + return LLDB_INVALID_THREAD_ID; +} + +// TODO implement +#if 0 +thread_t +NativeThreadListDarwin::GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const +{ + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + MachThreadSP thread_sp; + const size_t num_threads = m_threads.size(); + for (size_t idx = 0; idx < num_threads; ++idx) + { + if (m_threads[idx]->ThreadID() == globally_unique_id) + { + return m_threads[idx]->MachPortNumber(); + } + } + return 0; +} + +bool +NativeThreadListDarwin::GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value ) const +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetRegisterValue(set, reg, reg_value); + + return false; +} + +bool +NativeThreadListDarwin::SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value ) const +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->SetRegisterValue(set, reg, reg_value); + + return false; +} + +nub_size_t +NativeThreadListDarwin::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->GetRegisterContext (buf, buf_len); + return 0; +} + +nub_size_t +NativeThreadListDarwin::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->SetRegisterContext (buf, buf_len); + return 0; +} + +uint32_t +NativeThreadListDarwin::SaveRegisterState (nub_thread_t tid) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->SaveRegisterState (); + return 0; +} + +bool +NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) +{ + MachThreadSP thread_sp (GetThreadByID (tid)); + if (thread_sp) + return thread_sp->RestoreRegisterState (save_id); + return 0; +} +#endif + +size_t NativeThreadListDarwin::GetNumberOfThreads() const { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + return static_cast<size_t>(m_threads.size()); +} + +// TODO implement +#if 0 +nub_thread_t +NativeThreadListDarwin::ThreadIDAtIndex (nub_size_t idx) const +{ + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + if (idx < m_threads.size()) + return m_threads[idx]->ThreadID(); + return INVALID_NUB_THREAD; +} + +nub_thread_t +NativeThreadListDarwin::CurrentThreadID ( ) +{ + MachThreadSP thread_sp; + CurrentThread(thread_sp); + if (thread_sp.get()) + return thread_sp->ThreadID(); + return INVALID_NUB_THREAD; +} + +#endif + +bool NativeThreadListDarwin::NotifyException(MachException::Data &exc) { + auto thread_sp = GetThreadByMachPortNumber(exc.thread_port); + if (thread_sp) { + thread_sp->NotifyException(exc); + return true; + } + return false; +} + +void NativeThreadListDarwin::Clear() { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + m_threads.clear(); +} + +uint32_t NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process, + bool update, + collection *new_threads) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + 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 (m_is_64_bit) + DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); + else + DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); +#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (m_is_64_bit) + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); + else + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); +#endif +#endif + } + + if (m_threads.empty() || update) { + thread_array_t thread_list = nullptr; + mach_msg_type_number_t thread_list_count = 0; + task_t task = process.GetTask(); + + 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); + } + } + } + + m_threads.swap(currThreads); + m_current_thread.reset(); + + // Free the vm memory given to us by ::task_threads() + vm_size_t thread_list_size = + (vm_size_t)(thread_list_count * sizeof(::thread_t)); + ::vm_deallocate(::mach_task_self(), (vm_address_t)thread_list, + thread_list_size); + } + } + return static_cast<uint32_t>(m_threads.size()); +} + +// TODO implement +#if 0 + +void +NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp) +{ + // locker will keep a mutex locked until it goes out of scope + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + if (m_current_thread.get() == NULL) + { + // Figure out which thread is going to be our current thread. + // This is currently done by finding the first thread in the list + // that has a valid exception. + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + if (m_threads[idx]->GetStopException().IsValid()) + { + m_current_thread = m_threads[idx]; + break; + } + } + } + thread_sp = m_current_thread; +} + +#endif + +void NativeThreadListDarwin::Dump(Stream &stream) const { + bool first = true; + + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + for (auto thread_sp : m_threads) { + if (thread_sp) { + // Handle newlines between thread entries. + if (first) + first = false; + else + stream.PutChar('\n'); + thread_sp->Dump(stream); + } + } +} + +void NativeThreadListDarwin::ProcessWillResume( + NativeProcessDarwin &process, const ResumeActionList &thread_actions) { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + + // Update our thread list, because sometimes libdispatch or the kernel + // will spawn threads while a task is suspended. + NativeThreadListDarwin::collection new_threads; + +// TODO implement this. +#if 0 + // First figure out if we were planning on running only one thread, and if + // so, force that thread to resume. + bool run_one_thread; + thread_t solo_thread = THREAD_NULL; + if ((thread_actions.GetSize() > 0) && + (thread_actions.NumActionsWithState(eStateStepping) + + thread_actions.NumActionsWithState (eStateRunning) == 1)) + { + run_one_thread = true; + const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); + size_t num_actions = thread_actions.GetSize(); + for (size_t i = 0; i < num_actions; i++, action_ptr++) + { + if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning) + { + solo_thread = action_ptr->tid; + break; + } + } + } + else + run_one_thread = false; +#endif + + UpdateThreadList(process, true, &new_threads); + +#if 0 + DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; + // If we are planning to run only one thread, any new threads should be suspended. + if (run_one_thread) + resume_new_threads.state = eStateSuspended; + + const size_t num_new_threads = new_threads.size(); + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + MachThread *thread = m_threads[idx].get(); + bool handled = false; + for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) + { + if (thread == new_threads[new_idx].get()) + { + thread->ThreadWillResume(&resume_new_threads); + handled = true; + break; + } + } + + if (!handled) + { + const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); + // There must always be a thread action for every thread. + assert (thread_action); + bool others_stopped = false; + if (solo_thread == thread->ThreadID()) + others_stopped = true; + thread->ThreadWillResume (thread_action, others_stopped); + } + } + + if (new_threads.size()) + { + for (uint32_t idx = 0; idx < num_new_threads; ++idx) + { + DNBLogThreadedIf (LOG_THREAD, "NativeThreadListDarwin::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)", + process->ProcessID(), + process->StopCount(), + new_threads[idx]->ThreadID(), + new_threads[idx]->IsUserReady()); + } + } +#endif +} + +uint32_t NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process) { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + + // Update our thread list. + UpdateThreadList(process, true); + + for (auto thread_sp : m_threads) { + if (thread_sp) + thread_sp->ThreadDidStop(); + } + return (uint32_t)m_threads.size(); +} + +//---------------------------------------------------------------------- +// Check each thread in our thread list to see if we should notify our +// client of the current halt in execution. +// +// Breakpoints can have callback functions associated with them than +// can return true to stop, or false to continue executing the inferior. +// +// RETURNS +// true if we should stop and notify our clients +// false if we should resume our child process and skip notification +//---------------------------------------------------------------------- +bool NativeThreadListDarwin::ShouldStop(bool &step_more) { + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex); + for (auto thread_sp : m_threads) { + if (thread_sp && thread_sp->ShouldStop(step_more)) + return true; + } + return false; +} + +// Implement. +#if 0 + +void +NativeThreadListDarwin::NotifyBreakpointChanged (const DNBBreakpoint *bp) +{ + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + m_threads[idx]->NotifyBreakpointChanged(bp); + } +} + + +uint32_t +NativeThreadListDarwin::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const +{ + if (bp != NULL) + { + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->EnableHardwareBreakpoint(bp); + } + return INVALID_NUB_HW_INDEX; +} + +bool +NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const +{ + if (bp != NULL) + { + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->DisableHardwareBreakpoint(bp); + } + return false; +} + +// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint() +// -> NativeThreadListDarwin::EnableHardwareWatchpoint(). +uint32_t +NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const +{ + uint32_t hw_index = INVALID_NUB_HW_INDEX; + if (wp != NULL) + { + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + // On Mac OS X we have to prime the control registers for new threads. We do this + // using the control register data for the first thread, for lack of a better way of choosing. + bool also_set_on_task = true; + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) + { + // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); + return INVALID_NUB_HW_INDEX; + } + also_set_on_task = false; + } + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + + } + return hw_index; +} + +bool +NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const +{ + if (wp != NULL) + { + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + + // On Mac OS X we have to prime the control registers for new threads. We do this + // using the control register data for the first thread, for lack of a better way of choosing. + bool also_set_on_task = true; + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) + { + // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); + return false; + } + also_set_on_task = false; + } + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + + return true; + } + return false; +} + +uint32_t +NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const +{ + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + // Use an arbitrary thread to retrieve the number of supported hardware watchpoints. + if (num_threads) + return m_threads[0]->NumSupportedHardwareWatchpoints(); + return 0; +} + +uint32_t +NativeThreadListDarwin::GetThreadIndexForThreadStoppedWithSignal (const int signo) const +{ + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); + uint32_t should_stop = false; + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) + { + if (m_threads[idx]->GetStopException().SoftSignal () == signo) + return idx; + } + return UINT32_MAX; +} + +#endif diff --git a/source/Plugins/Process/Darwin/NativeThreadListDarwin.h b/source/Plugins/Process/Darwin/NativeThreadListDarwin.h new file mode 100644 index 000000000000..2b194bcc1537 --- /dev/null +++ b/source/Plugins/Process/Darwin/NativeThreadListDarwin.h @@ -0,0 +1,139 @@ +//===-- NativeThreadListDarwin.h --------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/19/07. +// +//===----------------------------------------------------------------------===// + +#ifndef __NativeThreadListDarwin_h__ +#define __NativeThreadListDarwin_h__ + +#include <memory> +#include <mutex> +#include <vector> + +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" + +#include "MachException.h" + +// #include "ThreadInfo.h" + +namespace lldb_private { +namespace process_darwin { + +class NativeBreakpointDarwin; +class NativeProcessDarwin; + +class NativeThreadDarwin; +using NativeThreadDarwinSP = std::shared_ptr<NativeThreadDarwin>; + +class NativeThreadListDarwin { +public: + NativeThreadListDarwin(); + ~NativeThreadListDarwin(); + + void Clear(); + + void Dump(Stream &stream) const; + +// These methods will be accessed directly from NativeThreadDarwin +#if 0 + bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const; + bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value) const; + nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len); + nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len); + uint32_t SaveRegisterState (nub_thread_t tid); + bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); +#endif + + const char *GetThreadInfo(lldb::tid_t tid) const; + + void ProcessWillResume(NativeProcessDarwin &process, + const ResumeActionList &thread_actions); + + uint32_t ProcessDidStop(NativeProcessDarwin &process); + + bool NotifyException(MachException::Data &exc); + + bool ShouldStop(bool &step_more); + +// These methods will be accessed directly from NativeThreadDarwin +#if 0 + const char * GetName (nub_thread_t tid); + nub_state_t GetState (nub_thread_t tid); + nub_thread_t SetCurrentThread (nub_thread_t tid); +#endif + +// TODO: figure out if we need to add this to NativeThreadDarwin yet. +#if 0 + ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index); + nub_addr_t GetPThreadT (nub_thread_t tid); + nub_addr_t GetDispatchQueueT (nub_thread_t tid); + nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); +#endif + +// These methods will be accessed directly from NativeThreadDarwin +#if 0 + bool GetThreadStoppedReason (nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const; + void DumpThreadStoppedReason (nub_thread_t tid) const; + bool GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info); +#endif + + size_t GetNumberOfThreads() const; + + lldb::tid_t ThreadIDAtIndex(size_t idx) const; + + lldb::tid_t GetCurrentThreadID(); + + NativeThreadDarwinSP GetCurrentThread(); + + void NotifyBreakpointChanged(const NativeBreakpointDarwin *bp); + + uint32_t EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; + + bool DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const; + + uint32_t EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; + + bool DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const; + + uint32_t GetNumberOfSupportedHardwareWatchpoints() const; + + size_t GetThreadIndexForThreadStoppedWithSignal(const int signo) const; + + NativeThreadDarwinSP GetThreadByID(lldb::tid_t tid) const; + + NativeThreadDarwinSP + GetThreadByMachPortNumber(::thread_t mach_port_number) const; + + lldb::tid_t GetThreadIDByMachPortNumber(::thread_t mach_port_number) const; + + thread_t GetMachPortNumberByThreadID(lldb::tid_t globally_unique_id) const; + +protected: + typedef std::vector<NativeThreadDarwinSP> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + // Consider having this return an lldb_private::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__ diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp index 3cb1cec6983f..0b09296cb7fd 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp @@ -16,684 +16,603 @@ #include "lldb/Target/UnixSignals.h" // Project includes -#include "lldb/Breakpoint/Watchpoint.h" +#include "FreeBSDThread.h" +#include "POSIXStopInfo.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" +#include "ProcessFreeBSD.h" +#include "ProcessMonitor.h" +#include "ProcessPOSIXLog.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "RegisterContextPOSIXProcessMonitor_arm64.h" +#include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" -#include "lldb/Host/HostNativeThread.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/HostNativeThread.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" #include "llvm/ADT/SmallString.h" -#include "POSIXStopInfo.h" -#include "FreeBSDThread.h" -#include "ProcessFreeBSD.h" -#include "ProcessPOSIXLog.h" -#include "ProcessMonitor.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" -#include "RegisterContextPOSIXProcessMonitor_arm64.h" -#include "RegisterContextPOSIXProcessMonitor_mips64.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" -#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" -#include "Plugins/Process/Utility/UnwindLLDB.h" using namespace lldb; using namespace lldb_private; FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) - : Thread(process, tid), - m_frame_ap (), - m_breakpoint (), - m_thread_name_valid (false), - m_thread_name (), - m_posix_thread(NULL) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("FreeBSDThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid); - - // Set the current watchpoints for this thread. - Target &target = GetProcess()->GetTarget(); - const WatchpointList &wp_list = target.GetWatchpointList(); - size_t wp_size = wp_list.GetSize(); - - for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) - { - lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); - if (wp.get() && wp->IsEnabled()) - { - // This watchpoint as been enabled; obviously this "new" thread - // has been created since that watchpoint was enabled. Since - // the POSIXBreakpointProtocol has yet to be initialized, its - // m_watchpoints_initialized member will be FALSE. Attempting to - // read the debug status register to determine if a watchpoint - // has been hit would result in the zeroing of that register. - // Since the active debug registers would have been cloned when - // this thread was created, simply force the m_watchpoints_initized - // member to TRUE and avoid resetting dr6 and dr7. - GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); - } + : Thread(process, tid), m_frame_ap(), m_breakpoint(), + m_thread_name_valid(false), m_thread_name(), m_posix_thread(NULL) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf("FreeBSDThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid); + + // Set the current watchpoints for this thread. + Target &target = GetProcess()->GetTarget(); + const WatchpointList &wp_list = target.GetWatchpointList(); + size_t wp_size = wp_list.GetSize(); + + for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) { + lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); + if (wp.get() && wp->IsEnabled()) { + // This watchpoint as been enabled; obviously this "new" thread + // has been created since that watchpoint was enabled. Since + // the POSIXBreakpointProtocol has yet to be initialized, its + // m_watchpoints_initialized member will be FALSE. Attempting to + // read the debug status register to determine if a watchpoint + // has been hit would result in the zeroing of that register. + // Since the active debug registers would have been cloned when + // this thread was created, simply force the m_watchpoints_initized + // member to TRUE and avoid resetting dr6 and dr7. + GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); } + } } -FreeBSDThread::~FreeBSDThread() -{ - DestroyThread(); -} +FreeBSDThread::~FreeBSDThread() { DestroyThread(); } -ProcessMonitor & -FreeBSDThread::GetMonitor() -{ - ProcessSP base = GetProcess(); - ProcessFreeBSD &process = static_cast<ProcessFreeBSD&>(*base); - return process.GetMonitor(); +ProcessMonitor &FreeBSDThread::GetMonitor() { + ProcessSP base = GetProcess(); + ProcessFreeBSD &process = static_cast<ProcessFreeBSD &>(*base); + return process.GetMonitor(); } -void -FreeBSDThread::RefreshStateAfterStop() -{ - // Invalidate all registers in our register context. We don't set "force" to - // true because the stop reply packet might have had some register values - // that were expedited and these will already be copied into the register - // context by the time this function gets called. The KDPRegisterContext - // class has been made smart enough to detect when it needs to invalidate - // which registers are valid by putting hooks in the register read and - // register supply functions where they check the process stop ID and do - // the right thing. - //if (StateIsStoppedState(GetState()) - { - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded (force); - } +void FreeBSDThread::RefreshStateAfterStop() { + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The KDPRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + // if (StateIsStoppedState(GetState()) + { + const bool force = false; + GetRegisterContext()->InvalidateIfNeeded(force); + } } -const char * -FreeBSDThread::GetInfo() -{ - return NULL; -} +const char *FreeBSDThread::GetInfo() { return NULL; } -void -FreeBSDThread::SetName (const char *name) -{ - m_thread_name_valid = (name && name[0]); - if (m_thread_name_valid) - m_thread_name.assign (name); - else - m_thread_name.clear(); +void FreeBSDThread::SetName(const char *name) { + m_thread_name_valid = (name && name[0]); + if (m_thread_name_valid) + m_thread_name.assign(name); + else + m_thread_name.clear(); } -const char * -FreeBSDThread::GetName () -{ - if (!m_thread_name_valid) - { - llvm::SmallString<32> thread_name; - HostNativeThread::GetName(GetID(), thread_name); - m_thread_name = thread_name.c_str(); - m_thread_name_valid = true; - } +const char *FreeBSDThread::GetName() { + if (!m_thread_name_valid) { + llvm::SmallString<32> thread_name; + HostNativeThread::GetName(GetID(), thread_name); + m_thread_name = thread_name.c_str(); + m_thread_name_valid = true; + } - if (m_thread_name.empty()) - return NULL; - return m_thread_name.c_str(); + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); } -lldb::RegisterContextSP -FreeBSDThread::GetRegisterContext() -{ - if (!m_reg_context_sp) - { - m_posix_thread = NULL; - - RegisterInfoInterface *reg_interface = NULL; - const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); - - assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD); - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - reg_interface = new RegisterContextFreeBSD_arm64(target_arch); - break; - case llvm::Triple::arm: - reg_interface = new RegisterContextFreeBSD_arm(target_arch); - break; - case llvm::Triple::ppc: +lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { + if (!m_reg_context_sp) { + m_posix_thread = NULL; + + RegisterInfoInterface *reg_interface = NULL; + const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); + + assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD); + switch (target_arch.GetMachine()) { + case llvm::Triple::aarch64: + reg_interface = new RegisterInfoPOSIX_arm64(target_arch); + break; + case llvm::Triple::arm: + reg_interface = new RegisterContextFreeBSD_arm(target_arch); + break; + case llvm::Triple::ppc: #ifndef __powerpc64__ - reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); - break; + reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); + break; #endif - case llvm::Triple::ppc64: - reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); - break; - case llvm::Triple::mips64: - reg_interface = new RegisterContextFreeBSD_mips64(target_arch); - break; - case llvm::Triple::x86: - reg_interface = new RegisterContextFreeBSD_i386(target_arch); - break; - case llvm::Triple::x86_64: - reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); - break; - default: - llvm_unreachable("CPU not supported"); - } + case llvm::Triple::ppc64: + reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); + break; + case llvm::Triple::mips64: + reg_interface = new RegisterContextFreeBSD_mips64(target_arch); + break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(target_arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; + default: + llvm_unreachable("CPU not supported"); + } - switch (target_arch.GetMachine()) - { - case llvm::Triple::aarch64: - { - RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::arm: - { - RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::mips64: - { - RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - { - RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - case llvm::Triple::x86: - case llvm::Triple::x86_64: - { - RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); - m_posix_thread = reg_ctx; - m_reg_context_sp.reset(reg_ctx); - break; - } - default: - break; - } + switch (target_arch.GetMachine()) { + case llvm::Triple::aarch64: { + RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = + new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::arm: { + RegisterContextPOSIXProcessMonitor_arm *reg_ctx = + new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; } - return m_reg_context_sp; + case llvm::Triple::mips64: { + RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = + new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, + reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::ppc: + case llvm::Triple::ppc64: { + RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = + new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, + reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + case llvm::Triple::x86: + case llvm::Triple::x86_64: { + RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = + new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, + reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + break; + } + default: + break; + } + } + return m_reg_context_sp; } lldb::RegisterContextSP -FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) -{ - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("FreeBSDThread::%s ()", __FUNCTION__); - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) - reg_ctx_sp = GetRegisterContext(); - else - { - assert(GetUnwinder()); - reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame); - } +FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) { + lldb::RegisterContextSP reg_ctx_sp; + uint32_t concrete_frame_idx = 0; - return reg_ctx_sp; -} + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf("FreeBSDThread::%s ()", __FUNCTION__); -lldb::addr_t -FreeBSDThread::GetThreadPointer () -{ - ProcessMonitor &monitor = GetMonitor(); - addr_t addr; - if (monitor.ReadThreadPointer (GetID(), addr)) - return addr; - else - return LLDB_INVALID_ADDRESS; -} + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); -bool -FreeBSDThread::CalculateStopInfo() -{ - SetStopInfo (m_stop_info_sp); - return true; -} - -Unwind * -FreeBSDThread::GetUnwinder() -{ - if (m_unwinder_ap.get() == NULL) - m_unwinder_ap.reset(new UnwindLLDB(*this)); + if (concrete_frame_idx == 0) + reg_ctx_sp = GetRegisterContext(); + else { + assert(GetUnwinder()); + reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame); + } - return m_unwinder_ap.get(); + return reg_ctx_sp; } -void -FreeBSDThread::DidStop() -{ - // Don't set the thread state to stopped unless we really stopped. +lldb::addr_t FreeBSDThread::GetThreadPointer() { + ProcessMonitor &monitor = GetMonitor(); + addr_t addr; + if (monitor.ReadThreadPointer(GetID(), addr)) + return addr; + else + return LLDB_INVALID_ADDRESS; } -void -FreeBSDThread::WillResume(lldb::StateType resume_state) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf("tid %lu resume_state = %s", GetID(), - lldb_private::StateAsCString(resume_state)); - ProcessSP process_sp(GetProcess()); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); - int signo = GetResumeSignal(); - bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo); - - switch (resume_state) - { - case eStateSuspended: - case eStateStopped: - process->m_suspend_tids.push_back(GetID()); - break; - case eStateRunning: - process->m_run_tids.push_back(GetID()); - if (signo_valid) - process->m_resume_signo = signo; - break; - case eStateStepping: - process->m_step_tids.push_back(GetID()); - if (signo_valid) - process->m_resume_signo = signo; - break; - default: - break; - } +bool FreeBSDThread::CalculateStopInfo() { + SetStopInfo(m_stop_info_sp); + return true; } -bool -FreeBSDThread::Resume() -{ - lldb::StateType resume_state = GetResumeState(); - ProcessMonitor &monitor = GetMonitor(); - bool status; +Unwind *FreeBSDThread::GetUnwinder() { + if (m_unwinder_ap.get() == NULL) + m_unwinder_ap.reset(new UnwindLLDB(*this)); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("FreeBSDThread::%s (), resume_state = %s", __FUNCTION__, - StateAsCString(resume_state)); - - switch (resume_state) - { - default: - assert(false && "Unexpected state for resume!"); - status = false; - break; - - case lldb::eStateRunning: - SetState(resume_state); - status = monitor.Resume(GetID(), GetResumeSignal()); - break; - - case lldb::eStateStepping: - SetState(resume_state); - status = monitor.SingleStep(GetID(), GetResumeSignal()); - break; - case lldb::eStateStopped: - case lldb::eStateSuspended: - status = true; - break; - } - - return status; + return m_unwinder_ap.get(); } -void -FreeBSDThread::Notify(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("FreeBSDThread::%s () message kind = '%s' for tid %" PRIu64, - __FUNCTION__, message.PrintKind(), GetID()); - - switch (message.GetKind()) - { - default: - assert(false && "Unexpected message kind!"); - break; - - case ProcessMessage::eExitMessage: - // Nothing to be done. - break; - - case ProcessMessage::eLimboMessage: - LimboNotify(message); - break; - - case ProcessMessage::eSignalMessage: - SignalNotify(message); - break; - - case ProcessMessage::eSignalDeliveredMessage: - SignalDeliveredNotify(message); - break; - - case ProcessMessage::eTraceMessage: - TraceNotify(message); - break; - - case ProcessMessage::eBreakpointMessage: - BreakNotify(message); - break; - - case ProcessMessage::eWatchpointMessage: - WatchNotify(message); - break; +void FreeBSDThread::DidStop() { + // Don't set the thread state to stopped unless we really stopped. +} - case ProcessMessage::eCrashMessage: - CrashNotify(message); - break; +void FreeBSDThread::WillResume(lldb::StateType resume_state) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log) + log->Printf("tid %lu resume_state = %s", GetID(), + lldb_private::StateAsCString(resume_state)); + ProcessSP process_sp(GetProcess()); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); + int signo = GetResumeSignal(); + bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo); + + switch (resume_state) { + case eStateSuspended: + case eStateStopped: + process->m_suspend_tids.push_back(GetID()); + break; + case eStateRunning: + process->m_run_tids.push_back(GetID()); + if (signo_valid) + process->m_resume_signo = signo; + break; + case eStateStepping: + process->m_step_tids.push_back(GetID()); + if (signo_valid) + process->m_resume_signo = signo; + break; + default: + break; + } +} - case ProcessMessage::eExecMessage: - ExecNotify(message); - break; - } +bool FreeBSDThread::Resume() { + lldb::StateType resume_state = GetResumeState(); + ProcessMonitor &monitor = GetMonitor(); + bool status; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log) + log->Printf("FreeBSDThread::%s (), resume_state = %s", __FUNCTION__, + StateAsCString(resume_state)); + + switch (resume_state) { + default: + assert(false && "Unexpected state for resume!"); + status = false; + break; + + case lldb::eStateRunning: + SetState(resume_state); + status = monitor.Resume(GetID(), GetResumeSignal()); + break; + + case lldb::eStateStepping: + SetState(resume_state); + status = monitor.SingleStep(GetID(), GetResumeSignal()); + break; + case lldb::eStateStopped: + case lldb::eStateSuspended: + status = true; + break; + } + + return status; } -bool -FreeBSDThread::EnableHardwareWatchpoint(Watchpoint *wp) -{ - bool wp_set = false; - if (wp) - { - addr_t wp_addr = wp->GetLoadAddress(); - size_t wp_size = wp->GetByteSize(); - bool wp_read = wp->WatchpointRead(); - bool wp_write = wp->WatchpointWrite(); - uint32_t wp_hw_index = wp->GetHardwareIndex(); - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size, - wp_read, wp_write, - wp_hw_index); - } - return wp_set; +void FreeBSDThread::Notify(const ProcessMessage &message) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log) + log->Printf("FreeBSDThread::%s () message kind = '%s' for tid %" PRIu64, + __FUNCTION__, message.PrintKind(), GetID()); + + switch (message.GetKind()) { + default: + assert(false && "Unexpected message kind!"); + break; + + case ProcessMessage::eExitMessage: + // Nothing to be done. + break; + + case ProcessMessage::eLimboMessage: + LimboNotify(message); + break; + + case ProcessMessage::eSignalMessage: + SignalNotify(message); + break; + + case ProcessMessage::eSignalDeliveredMessage: + SignalDeliveredNotify(message); + break; + + case ProcessMessage::eTraceMessage: + TraceNotify(message); + break; + + case ProcessMessage::eBreakpointMessage: + BreakNotify(message); + break; + + case ProcessMessage::eWatchpointMessage: + WatchNotify(message); + break; + + case ProcessMessage::eCrashMessage: + CrashNotify(message); + break; + + case ProcessMessage::eExecMessage: + ExecNotify(message); + break; + } } -bool -FreeBSDThread::DisableHardwareWatchpoint(Watchpoint *wp) -{ - bool result = false; - if (wp) - { - lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); - if (reg_ctx_sp.get()) - result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); - } - return result; +bool FreeBSDThread::EnableHardwareWatchpoint(Watchpoint *wp) { + bool wp_set = false; + if (wp) { + addr_t wp_addr = wp->GetLoadAddress(); + size_t wp_size = wp->GetByteSize(); + bool wp_read = wp->WatchpointRead(); + bool wp_write = wp->WatchpointWrite(); + uint32_t wp_hw_index = wp->GetHardwareIndex(); + POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + wp_set = reg_ctx->SetHardwareWatchpointWithIndex( + wp_addr, wp_size, wp_read, wp_write, wp_hw_index); + } + return wp_set; } -uint32_t -FreeBSDThread::NumSupportedHardwareWatchpoints() -{ +bool FreeBSDThread::DisableHardwareWatchpoint(Watchpoint *wp) { + bool result = false; + if (wp) { lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); if (reg_ctx_sp.get()) - return reg_ctx_sp->NumSupportedHardwareWatchpoints(); - return 0; + result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); + } + return result; } -uint32_t -FreeBSDThread::FindVacantWatchpointIndex() -{ - uint32_t hw_index = LLDB_INVALID_INDEX32; - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointVacant(wp_idx)) - { - hw_index = wp_idx; - break; - } - } +uint32_t FreeBSDThread::NumSupportedHardwareWatchpoints() { + lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); + if (reg_ctx_sp.get()) + return reg_ctx_sp->NumSupportedHardwareWatchpoints(); + return 0; +} + +uint32_t FreeBSDThread::FindVacantWatchpointIndex() { + uint32_t hw_index = LLDB_INVALID_INDEX32; + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) { + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { + if (reg_ctx->IsWatchpointVacant(wp_idx)) { + hw_index = wp_idx; + break; + } } - return hw_index; + } + return hw_index; } -void -FreeBSDThread::BreakNotify(const ProcessMessage &message) -{ - bool status; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - - assert(GetRegisterContext()); - status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); - assert(status && "Breakpoint update failed!"); - - // With our register state restored, resolve the breakpoint object - // corresponding to our current PC. - assert(GetRegisterContext()); - lldb::addr_t pc = GetRegisterContext()->GetPC(); - if (log) - log->Printf ("FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); - lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - - // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we create a stop reason with should_stop=false. If there is no breakpoint location, then report - // an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will - // be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - if (bp_site) - { - lldb::break_id_t bp_id = bp_site->GetID(); - // If we have an operating system plug-in, we might have set a thread specific breakpoint using the - // operating system thread ID, so we can't make any assumptions about the thread ID so we must always - // report the breakpoint regardless of the thread. - if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL) - SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); - else - { - const bool should_stop = false; - SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop)); - } +void FreeBSDThread::BreakNotify(const ProcessMessage &message) { + bool status; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + + assert(GetRegisterContext()); + status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); + assert(status && "Breakpoint update failed!"); + + // With our register state restored, resolve the breakpoint object + // corresponding to our current PC. + assert(GetRegisterContext()); + lldb::addr_t pc = GetRegisterContext()->GetPC(); + if (log) + log->Printf("FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); + lldb::BreakpointSiteSP bp_site( + GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); + + // If the breakpoint is for this thread, then we'll report the hit, but if it + // is for another thread, + // we create a stop reason with should_stop=false. If there is no breakpoint + // location, then report + // an invalid stop reason. We don't need to worry about stepping over the + // breakpoint here, that will + // be taken care of when the thread resumes and notices that there's a + // breakpoint under the pc. + if (bp_site) { + lldb::break_id_t bp_id = bp_site->GetID(); + // If we have an operating system plug-in, we might have set a thread + // specific breakpoint using the + // operating system thread ID, so we can't make any assumptions about the + // thread ID so we must always + // report the breakpoint regardless of the thread. + if (bp_site->ValidForThisThread(this) || + GetProcess()->GetOperatingSystem() != NULL) + SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); + else { + const bool should_stop = false; + SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, + should_stop)); } - else - SetStopInfo(StopInfoSP()); + } else + SetStopInfo(StopInfoSP()); } -void -FreeBSDThread::WatchNotify(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); +void FreeBSDThread::WatchNotify(const ProcessMessage &message) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - lldb::addr_t halt_addr = message.GetHWAddress(); - if (log) - log->Printf ("FreeBSDThread::%s () Hardware Watchpoint Address = 0x%8.8" - PRIx64, __FUNCTION__, halt_addr); + lldb::addr_t halt_addr = message.GetHWAddress(); + if (log) + log->Printf( + "FreeBSDThread::%s () Hardware Watchpoint Address = 0x%8.8" PRIx64, + __FUNCTION__, halt_addr); - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointHit(wp_idx)) - { - // Clear the watchpoint hit here - reg_ctx->ClearWatchpointHits(); - break; - } - } + POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { + if (reg_ctx->IsWatchpointHit(wp_idx)) { + // Clear the watchpoint hit here + reg_ctx->ClearWatchpointHits(); + break; + } + } - if (wp_idx == num_hw_wps) - return; + if (wp_idx == num_hw_wps) + return; - Target &target = GetProcess()->GetTarget(); - lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); - const WatchpointList &wp_list = target.GetWatchpointList(); - lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); + Target &target = GetProcess()->GetTarget(); + lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); + const WatchpointList &wp_list = target.GetWatchpointList(); + lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); - assert(wp_sp.get() && "No watchpoint found"); - SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this, - wp_sp->GetID())); - } + assert(wp_sp.get() && "No watchpoint found"); + SetStopInfo( + StopInfo::CreateStopReasonWithWatchpointID(*this, wp_sp->GetID())); + } } -void -FreeBSDThread::TraceNotify(const ProcessMessage &message) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - - // Try to resolve the breakpoint object corresponding to the current PC. - assert(GetRegisterContext()); - lldb::addr_t pc = GetRegisterContext()->GetPC(); - if (log) - log->Printf ("FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); - lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); - - // If the current pc is a breakpoint site then set the StopInfo to Breakpoint. - // Otherwise, set the StopInfo to Watchpoint or Trace. - // If we have an operating system plug-in, we might have set a thread specific breakpoint using the - // operating system thread ID, so we can't make any assumptions about the thread ID so we must always - // report the breakpoint regardless of the thread. - if (bp_site && (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL)) - SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_site->GetID())); - else - { - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - if (reg_ctx) - { - uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); - uint32_t wp_idx; - for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) - { - if (reg_ctx->IsWatchpointHit(wp_idx)) - { - WatchNotify(message); - return; - } - } +void FreeBSDThread::TraceNotify(const ProcessMessage &message) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + + // Try to resolve the breakpoint object corresponding to the current PC. + assert(GetRegisterContext()); + lldb::addr_t pc = GetRegisterContext()->GetPC(); + if (log) + log->Printf("FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); + lldb::BreakpointSiteSP bp_site( + GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); + + // If the current pc is a breakpoint site then set the StopInfo to Breakpoint. + // Otherwise, set the StopInfo to Watchpoint or Trace. + // If we have an operating system plug-in, we might have set a thread specific + // breakpoint using the + // operating system thread ID, so we can't make any assumptions about the + // thread ID so we must always + // report the breakpoint regardless of the thread. + if (bp_site && (bp_site->ValidForThisThread(this) || + GetProcess()->GetOperatingSystem() != NULL)) + SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( + *this, bp_site->GetID())); + else { + POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { + if (reg_ctx->IsWatchpointHit(wp_idx)) { + WatchNotify(message); + return; } - SetStopInfo (StopInfo::CreateStopReasonToTrace(*this)); + } } + SetStopInfo(StopInfo::CreateStopReasonToTrace(*this)); + } } -void -FreeBSDThread::LimboNotify(const ProcessMessage &message) -{ - SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); +void FreeBSDThread::LimboNotify(const ProcessMessage &message) { + SetStopInfo(lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); } -void -FreeBSDThread::SignalNotify(const ProcessMessage &message) -{ - int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); +void FreeBSDThread::SignalNotify(const ProcessMessage &message) { + int signo = message.GetSignal(); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); } -void -FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) -{ - int signo = message.GetSignal(); - SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo)); +void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) { + int signo = message.GetSignal(); + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); } -void -FreeBSDThread::CrashNotify(const ProcessMessage &message) -{ - // FIXME: Update stop reason as per bugzilla 14598 - int signo = message.GetSignal(); +void FreeBSDThread::CrashNotify(const ProcessMessage &message) { + // FIXME: Update stop reason as per bugzilla 14598 + int signo = message.GetSignal(); - assert(message.GetKind() == ProcessMessage::eCrashMessage); + assert(message.GetKind() == ProcessMessage::eCrashMessage); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); - if (log) - log->Printf ("FreeBSDThread::%s () signo = %i, reason = '%s'", - __FUNCTION__, signo, message.PrintCrashReason()); + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log) + log->Printf("FreeBSDThread::%s () signo = %i, reason = '%s'", __FUNCTION__, + signo, message.PrintCrashReason()); - SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo, - message.GetCrashReason(), - message.GetFaultAddress()))); + SetStopInfo(lldb::StopInfoSP(new POSIXCrashStopInfo( + *this, signo, message.GetCrashReason(), message.GetFaultAddress()))); } -unsigned -FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg = LLDB_INVALID_REGNUM; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) - { - default: - llvm_unreachable("CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - { - POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); - reg = reg_ctx->GetRegisterIndexFromOffset(offset); - } - break; - } - return reg; +unsigned FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) { + unsigned reg = LLDB_INVALID_REGNUM; + ArchSpec arch = HostInfo::GetArchitecture(); + + switch (arch.GetMachine()) { + default: + llvm_unreachable("CPU type not supported!"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: { + POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); + reg = reg_ctx->GetRegisterIndexFromOffset(offset); + } break; + } + return reg; } -void -FreeBSDThread::ExecNotify(const ProcessMessage &message) -{ - SetStopInfo (StopInfo::CreateStopReasonWithExec(*this)); +void FreeBSDThread::ExecNotify(const ProcessMessage &message) { + SetStopInfo(StopInfo::CreateStopReasonWithExec(*this)); } -const char * -FreeBSDThread::GetRegisterName(unsigned reg) -{ - const char * name = nullptr; - ArchSpec arch = HostInfo::GetArchitecture(); - - switch (arch.GetMachine()) - { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::arm: - case llvm::Triple::mips64: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - name = GetRegisterContext()->GetRegisterName(reg); - break; - } - return name; +const char *FreeBSDThread::GetRegisterName(unsigned reg) { + const char *name = nullptr; + ArchSpec arch = HostInfo::GetArchitecture(); + + switch (arch.GetMachine()) { + default: + assert(false && "CPU type not supported!"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::arm: + case llvm::Triple::mips64: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + name = GetRegisterContext()->GetRegisterName(reg); + break; + } + return name; } -const char * -FreeBSDThread::GetRegisterNameFromOffset(unsigned offset) -{ - return GetRegisterName(GetRegisterIndexFromOffset(offset)); +const char *FreeBSDThread::GetRegisterNameFromOffset(unsigned offset) { + return GetRegisterName(GetRegisterIndexFromOffset(offset)); } - diff --git a/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/source/Plugins/Process/FreeBSD/FreeBSDThread.h index 90c11dbefcb0..72e846459552 100644 --- a/source/Plugins/Process/FreeBSD/FreeBSDThread.h +++ b/source/Plugins/Process/FreeBSD/FreeBSDThread.h @@ -15,8 +15,8 @@ #include <string> // Other libraries and framework includes -#include "lldb/Target/Thread.h" #include "RegisterContextPOSIX.h" +#include "lldb/Target/Thread.h" class ProcessMessage; class ProcessMonitor; @@ -25,118 +25,99 @@ class POSIXBreakpointProtocol; //------------------------------------------------------------------------------ // @class FreeBSDThread // @brief Abstraction of a FreeBSD thread. -class FreeBSDThread - : public lldb_private::Thread -{ +class FreeBSDThread : public lldb_private::Thread { public: + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); - - virtual ~FreeBSDThread(); + virtual ~FreeBSDThread(); - // POSIXThread - void - RefreshStateAfterStop() override; + // POSIXThread + void RefreshStateAfterStop() override; - // This notifies the thread when a private stop occurs. - void - DidStop () override; + // This notifies the thread when a private stop occurs. + void DidStop() override; - const char * - GetInfo() override; + const char *GetInfo() override; - void - SetName (const char *name) override; + void SetName(const char *name) override; - const char * - GetName () override; + const char *GetName() override; - lldb::RegisterContextSP - GetRegisterContext() override; + lldb::RegisterContextSP GetRegisterContext() override; - lldb::RegisterContextSP - CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override; + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - lldb::addr_t - GetThreadPointer () override; + lldb::addr_t GetThreadPointer() override; - //-------------------------------------------------------------------------- - // These functions provide a mapping from the register offset - // back to the register index or name for use in debugging or log - // output. + //-------------------------------------------------------------------------- + // These functions provide a mapping from the register offset + // back to the register index or name for use in debugging or log + // output. - unsigned - GetRegisterIndexFromOffset(unsigned offset); + unsigned GetRegisterIndexFromOffset(unsigned offset); - const char * - GetRegisterName(unsigned reg); + const char *GetRegisterName(unsigned reg); - const char * - GetRegisterNameFromOffset(unsigned offset); + const char *GetRegisterNameFromOffset(unsigned offset); - //-------------------------------------------------------------------------- - // These methods form a specialized interface to POSIX threads. - // - bool Resume(); + //-------------------------------------------------------------------------- + // These methods form a specialized interface to POSIX threads. + // + bool Resume(); - void Notify(const ProcessMessage &message); + void Notify(const ProcessMessage &message); - //-------------------------------------------------------------------------- - // These methods provide an interface to watchpoints - // - bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); + //-------------------------------------------------------------------------- + // These methods provide an interface to watchpoints + // + bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp); - bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); + bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp); - uint32_t NumSupportedHardwareWatchpoints(); + uint32_t NumSupportedHardwareWatchpoints(); - uint32_t FindVacantWatchpointIndex(); + uint32_t FindVacantWatchpointIndex(); protected: - POSIXBreakpointProtocol * - GetPOSIXBreakpointProtocol () - { - if (!m_reg_context_sp) - m_reg_context_sp = GetRegisterContext(); - return m_posix_thread; - } - - std::unique_ptr<lldb_private::StackFrame> m_frame_ap; - - lldb::BreakpointSiteSP m_breakpoint; - - bool m_thread_name_valid; - std::string m_thread_name; - POSIXBreakpointProtocol *m_posix_thread; - - ProcessMonitor & - GetMonitor(); - - bool - CalculateStopInfo() override; - - void BreakNotify(const ProcessMessage &message); - void WatchNotify(const ProcessMessage &message); - virtual void TraceNotify(const ProcessMessage &message); - void LimboNotify(const ProcessMessage &message); - void SignalNotify(const ProcessMessage &message); - void SignalDeliveredNotify(const ProcessMessage &message); - void CrashNotify(const ProcessMessage &message); - void ExitNotify(const ProcessMessage &message); - void ExecNotify(const ProcessMessage &message); - - lldb_private::Unwind * - GetUnwinder() override; - - //-------------------------------------------------------------------------- - // FreeBSDThread internal API. - - // POSIXThread override - virtual void - WillResume(lldb::StateType resume_state) override; + POSIXBreakpointProtocol *GetPOSIXBreakpointProtocol() { + if (!m_reg_context_sp) + m_reg_context_sp = GetRegisterContext(); + return m_posix_thread; + } + + std::unique_ptr<lldb_private::StackFrame> m_frame_ap; + + lldb::BreakpointSiteSP m_breakpoint; + + bool m_thread_name_valid; + std::string m_thread_name; + POSIXBreakpointProtocol *m_posix_thread; + + ProcessMonitor &GetMonitor(); + + bool CalculateStopInfo() override; + + void BreakNotify(const ProcessMessage &message); + void WatchNotify(const ProcessMessage &message); + virtual void TraceNotify(const ProcessMessage &message); + void LimboNotify(const ProcessMessage &message); + void SignalNotify(const ProcessMessage &message); + void SignalDeliveredNotify(const ProcessMessage &message); + void CrashNotify(const ProcessMessage &message); + void ExitNotify(const ProcessMessage &message); + void ExecNotify(const ProcessMessage &message); + + lldb_private::Unwind *GetUnwinder() override; + + //-------------------------------------------------------------------------- + // FreeBSDThread internal API. + + // POSIXThread override + virtual void WillResume(lldb::StateType resume_state) override; }; #endif // #ifndef liblldb_FreeBSDThread_H_ diff --git a/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp index 409cf8c46b03..dfbd695899ff 100644 --- a/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp +++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp @@ -12,81 +12,50 @@ using namespace lldb; using namespace lldb_private; - //===----------------------------------------------------------------------===// // POSIXLimboStopInfo -POSIXLimboStopInfo::~POSIXLimboStopInfo() { } +POSIXLimboStopInfo::~POSIXLimboStopInfo() {} -lldb::StopReason -POSIXLimboStopInfo::GetStopReason() const -{ - return lldb::eStopReasonThreadExiting; +lldb::StopReason POSIXLimboStopInfo::GetStopReason() const { + return lldb::eStopReasonThreadExiting; } -const char * -POSIXLimboStopInfo::GetDescription() -{ - return "thread exiting"; -} +const char *POSIXLimboStopInfo::GetDescription() { return "thread exiting"; } -bool -POSIXLimboStopInfo::ShouldStop(Event *event_ptr) -{ - return false; -} +bool POSIXLimboStopInfo::ShouldStop(Event *event_ptr) { return false; } -bool -POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) -{ - return false; -} +bool POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) { return false; } //===----------------------------------------------------------------------===// // POSIXCrashStopInfo -POSIXCrashStopInfo::POSIXCrashStopInfo(FreeBSDThread &thread, - uint32_t status, +POSIXCrashStopInfo::POSIXCrashStopInfo(FreeBSDThread &thread, uint32_t status, CrashReason reason, lldb::addr_t fault_addr) - : POSIXStopInfo(thread, status) -{ - m_description = ::GetCrashReasonString(reason, fault_addr); + : POSIXStopInfo(thread, status) { + m_description = ::GetCrashReasonString(reason, fault_addr); } -POSIXCrashStopInfo::~POSIXCrashStopInfo() { } +POSIXCrashStopInfo::~POSIXCrashStopInfo() {} -lldb::StopReason -POSIXCrashStopInfo::GetStopReason() const -{ - return lldb::eStopReasonException; +lldb::StopReason POSIXCrashStopInfo::GetStopReason() const { + return lldb::eStopReasonException; } //===----------------------------------------------------------------------===// // POSIXNewThreadStopInfo -POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { } +POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() {} -lldb::StopReason -POSIXNewThreadStopInfo::GetStopReason() const -{ - return lldb::eStopReasonNone; +lldb::StopReason POSIXNewThreadStopInfo::GetStopReason() const { + return lldb::eStopReasonNone; } -const char * -POSIXNewThreadStopInfo::GetDescription() -{ - return "thread spawned"; +const char *POSIXNewThreadStopInfo::GetDescription() { + return "thread spawned"; } -bool -POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) -{ - return false; -} +bool POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) { return false; } -bool -POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) -{ - return false; -} +bool POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) { return false; } diff --git a/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h index ace6c98017b7..1ee16dd5f8f4 100644 --- a/source/Plugins/Process/FreeBSD/POSIXStopInfo.h +++ b/source/Plugins/Process/FreeBSD/POSIXStopInfo.h @@ -25,58 +25,42 @@ /// @class POSIXStopInfo /// @brief Simple base class for all POSIX-specific StopInfo objects. /// -class POSIXStopInfo - : public lldb_private::StopInfo -{ +class POSIXStopInfo : public lldb_private::StopInfo { public: - POSIXStopInfo(lldb_private::Thread &thread, uint32_t status) - : StopInfo(thread, status) - { } + POSIXStopInfo(lldb_private::Thread &thread, uint32_t status) + : StopInfo(thread, status) {} }; //===----------------------------------------------------------------------===// /// @class POSIXLimboStopInfo /// @brief Represents the stop state of a process ready to exit. /// -class POSIXLimboStopInfo - : public POSIXStopInfo -{ +class POSIXLimboStopInfo : public POSIXStopInfo { public: - POSIXLimboStopInfo(FreeBSDThread &thread) - : POSIXStopInfo(thread, 0) - { } + POSIXLimboStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {} - ~POSIXLimboStopInfo(); + ~POSIXLimboStopInfo(); - lldb::StopReason - GetStopReason() const; + lldb::StopReason GetStopReason() const; - const char * - GetDescription(); + const char *GetDescription(); - bool - ShouldStop(lldb_private::Event *event_ptr); + bool ShouldStop(lldb_private::Event *event_ptr); - bool - ShouldNotify(lldb_private::Event *event_ptr); + bool ShouldNotify(lldb_private::Event *event_ptr); }; - //===----------------------------------------------------------------------===// /// @class POSIXCrashStopInfo /// @brief Represents the stop state of process that is ready to crash. /// -class POSIXCrashStopInfo - : public POSIXStopInfo -{ +class POSIXCrashStopInfo : public POSIXStopInfo { public: - POSIXCrashStopInfo(FreeBSDThread &thread, uint32_t status, - CrashReason reason, - lldb::addr_t fault_addr); - ~POSIXCrashStopInfo(); + POSIXCrashStopInfo(FreeBSDThread &thread, uint32_t status, CrashReason reason, + lldb::addr_t fault_addr); + ~POSIXCrashStopInfo(); - lldb::StopReason - GetStopReason() const; + lldb::StopReason GetStopReason() const; }; //===----------------------------------------------------------------------===// @@ -84,27 +68,19 @@ public: /// @brief Represents the stop state of process when a new thread is spawned. /// -class POSIXNewThreadStopInfo - : public POSIXStopInfo -{ +class POSIXNewThreadStopInfo : public POSIXStopInfo { public: - POSIXNewThreadStopInfo (FreeBSDThread &thread) - : POSIXStopInfo (thread, 0) - { } + POSIXNewThreadStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {} - ~POSIXNewThreadStopInfo(); + ~POSIXNewThreadStopInfo(); - lldb::StopReason - GetStopReason() const; + lldb::StopReason GetStopReason() const; - const char * - GetDescription(); + const char *GetDescription(); - bool - ShouldStop(lldb_private::Event *event_ptr); + bool ShouldStop(lldb_private::Event *event_ptr); - bool - ShouldNotify(lldb_private::Event *event_ptr); + bool ShouldNotify(lldb_private::Event *event_ptr); }; #endif diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 3a72a65da696..82e45a5d5fc1 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -1,4 +1,5 @@ -//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -*-===// +//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -21,12 +22,12 @@ #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" -#include "ProcessFreeBSD.h" -#include "ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "FreeBSDThread.h" #include "Plugins/Process/Utility/FreeBSDSignals.h" +#include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "ProcessFreeBSD.h" #include "ProcessMonitor.h" -#include "FreeBSDThread.h" +#include "ProcessPOSIXLog.h" // Other libraries and framework includes #include "lldb/Breakpoint/BreakpointLocation.h" @@ -44,18 +45,14 @@ #include "lldb/Host/posix/Fcntl.h" - using namespace lldb; using namespace lldb_private; -namespace -{ - UnixSignalsSP& - GetFreeBSDSignals () - { - static UnixSignalsSP s_freebsd_signals_sp (new FreeBSDSignals ()); - return s_freebsd_signals_sp; - } +namespace { +UnixSignalsSP &GetFreeBSDSignals() { + static UnixSignalsSP s_freebsd_signals_sp(new FreeBSDSignals()); + return s_freebsd_signals_sp; +} } //------------------------------------------------------------------------------ @@ -64,869 +61,756 @@ namespace lldb::ProcessSP ProcessFreeBSD::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path) -{ - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset(new ProcessFreeBSD (target_sp, listener_sp, GetFreeBSDSignals())); - return process_sp; + const FileSpec *crash_file_path) { + lldb::ProcessSP process_sp; + if (crash_file_path == NULL) + process_sp.reset( + new ProcessFreeBSD(target_sp, listener_sp, GetFreeBSDSignals())); + return process_sp; } -void -ProcessFreeBSD::Initialize() -{ - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); - ProcessPOSIXLog::Initialize(GetPluginNameStatic()); - }); +void ProcessFreeBSD::Initialize() { + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + ProcessPOSIXLog::Initialize(GetPluginNameStatic()); + }); } -lldb_private::ConstString -ProcessFreeBSD::GetPluginNameStatic() -{ - static ConstString g_name("freebsd"); - return g_name; +lldb_private::ConstString ProcessFreeBSD::GetPluginNameStatic() { + static ConstString g_name("freebsd"); + return g_name; } -const char * -ProcessFreeBSD::GetPluginDescriptionStatic() -{ - return "Process plugin for FreeBSD"; +const char *ProcessFreeBSD::GetPluginDescriptionStatic() { + return "Process plugin for FreeBSD"; } //------------------------------------------------------------------------------ // ProcessInterface protocol. -lldb_private::ConstString -ProcessFreeBSD::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ProcessFreeBSD::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ProcessFreeBSD::GetPluginVersion() -{ - return 1; -} +uint32_t ProcessFreeBSD::GetPluginVersion() { return 1; } -void -ProcessFreeBSD::Terminate() -{ -} - -Error -ProcessFreeBSD::DoDetach(bool keep_stopped) -{ - Error error; - if (keep_stopped) - { - error.SetErrorString("Detaching with keep_stopped true is not currently supported on FreeBSD."); - return error; - } - - error = m_monitor->Detach(GetID()); - - if (error.Success()) - SetPrivateState(eStateDetached); +void ProcessFreeBSD::Terminate() {} +Error ProcessFreeBSD::DoDetach(bool keep_stopped) { + Error error; + if (keep_stopped) { + error.SetErrorString("Detaching with keep_stopped true is not currently " + "supported on FreeBSD."); return error; -} - -Error -ProcessFreeBSD::DoResume() -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - SetPrivateState(eStateRunning); - - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - bool do_step = false; + } + + error = m_monitor->Detach(GetID()); + + if (error.Success()) + SetPrivateState(eStateDetached); + + return error; +} + +Error ProcessFreeBSD::DoResume() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + SetPrivateState(eStateRunning); + + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + bool do_step = false; + + for (tid_collection::const_iterator t_pos = m_run_tids.begin(), + t_end = m_run_tids.end(); + t_pos != t_end; ++t_pos) { + m_monitor->ThreadSuspend(*t_pos, false); + } + for (tid_collection::const_iterator t_pos = m_step_tids.begin(), + t_end = m_step_tids.end(); + t_pos != t_end; ++t_pos) { + m_monitor->ThreadSuspend(*t_pos, false); + do_step = true; + } + for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), + t_end = m_suspend_tids.end(); + t_pos != t_end; ++t_pos) { + m_monitor->ThreadSuspend(*t_pos, true); + // XXX Cannot PT_CONTINUE properly with suspended threads. + do_step = true; + } + + if (log) + log->Printf("process %" PRIu64 " resuming (%s)", GetID(), + do_step ? "step" : "continue"); + if (do_step) + m_monitor->SingleStep(GetID(), m_resume_signo); + else + m_monitor->Resume(GetID(), m_resume_signo); + + return Error(); +} + +bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + if (log) + log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, + GetID()); + + std::vector<lldb::pid_t> tds; + if (!GetMonitor().GetCurrentThreadIDs(tds)) { + return false; + } - for (tid_collection::const_iterator t_pos = m_run_tids.begin(), t_end = m_run_tids.end(); t_pos != t_end; ++t_pos) - { - m_monitor->ThreadSuspend(*t_pos, false); - } - for (tid_collection::const_iterator t_pos = m_step_tids.begin(), t_end = m_step_tids.end(); t_pos != t_end; ++t_pos) - { - m_monitor->ThreadSuspend(*t_pos, false); - do_step = true; + ThreadList old_thread_list_copy(old_thread_list); + for (size_t i = 0; i < tds.size(); ++i) { + tid_t tid = tds[i]; + ThreadSP thread_sp(old_thread_list_copy.RemoveThreadByID(tid, false)); + if (!thread_sp) { + thread_sp.reset(new FreeBSDThread(*this, tid)); + if (log) + log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid); + } else { + if (log) + log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, + tid); } - for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), t_end = m_suspend_tids.end(); t_pos != t_end; ++t_pos) - { - m_monitor->ThreadSuspend(*t_pos, true); - // XXX Cannot PT_CONTINUE properly with suspended threads. - do_step = true; + new_thread_list.AddThread(thread_sp); + } + for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) { + ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); + if (old_thread_sp) { + if (log) + log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__); } + } - if (log) - log->Printf("process %" PRIu64 " resuming (%s)", GetID(), do_step ? "step" : "continue"); - if (do_step) - m_monitor->SingleStep(GetID(), m_resume_signo); - else - m_monitor->Resume(GetID(), m_resume_signo); - - return Error(); + return true; } -bool -ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - - std::vector<lldb::pid_t> tds; - if (!GetMonitor().GetCurrentThreadIDs(tds)) - { - return false; - } +Error ProcessFreeBSD::WillResume() { + m_resume_signo = 0; + m_suspend_tids.clear(); + m_run_tids.clear(); + m_step_tids.clear(); + return Process::WillResume(); +} - ThreadList old_thread_list_copy(old_thread_list); - for (size_t i = 0; i < tds.size(); ++i) - { - tid_t tid = tds[i]; - ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false)); - if (!thread_sp) - { - thread_sp.reset(new FreeBSDThread(*this, tid)); - if (log) - log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid); - } - else - { - if (log) - log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid); - } - new_thread_list.AddThread(thread_sp); - } - for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i) - { - ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false)); - if (old_thread_sp) - { - if (log) - log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__); - } - } +void ProcessFreeBSD::SendMessage(const ProcessMessage &message) { + std::lock_guard<std::recursive_mutex> guard(m_message_mutex); - return true; -} + switch (message.GetKind()) { + case ProcessMessage::eInvalidMessage: + return; -Error -ProcessFreeBSD::WillResume() -{ - m_resume_signo = 0; - m_suspend_tids.clear(); - m_run_tids.clear(); - m_step_tids.clear(); - return Process::WillResume(); -} + case ProcessMessage::eAttachMessage: + SetPrivateState(eStateStopped); + return; -void -ProcessFreeBSD::SendMessage(const ProcessMessage &message) -{ - std::lock_guard<std::recursive_mutex> guard(m_message_mutex); + case ProcessMessage::eLimboMessage: + case ProcessMessage::eExitMessage: + SetExitStatus(message.GetExitStatus(), NULL); + break; - switch (message.GetKind()) - { - case ProcessMessage::eInvalidMessage: - return; + case ProcessMessage::eSignalMessage: + case ProcessMessage::eSignalDeliveredMessage: + case ProcessMessage::eBreakpointMessage: + case ProcessMessage::eTraceMessage: + case ProcessMessage::eWatchpointMessage: + case ProcessMessage::eCrashMessage: + SetPrivateState(eStateStopped); + break; - case ProcessMessage::eAttachMessage: - SetPrivateState(eStateStopped); - return; + case ProcessMessage::eNewThreadMessage: + llvm_unreachable("eNewThreadMessage unexpected on FreeBSD"); + break; - case ProcessMessage::eLimboMessage: - case ProcessMessage::eExitMessage: - SetExitStatus(message.GetExitStatus(), NULL); - break; - - case ProcessMessage::eSignalMessage: - case ProcessMessage::eSignalDeliveredMessage: - case ProcessMessage::eBreakpointMessage: - case ProcessMessage::eTraceMessage: - case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eCrashMessage: - SetPrivateState(eStateStopped); - break; - - case ProcessMessage::eNewThreadMessage: - llvm_unreachable("eNewThreadMessage unexpected on FreeBSD"); - break; - - case ProcessMessage::eExecMessage: - SetPrivateState(eStateStopped); - break; - } + case ProcessMessage::eExecMessage: + SetPrivateState(eStateStopped); + break; + } - m_message_queue.push(message); + m_message_queue.push(message); } //------------------------------------------------------------------------------ // Constructors and destructors. -ProcessFreeBSD::ProcessFreeBSD(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, UnixSignalsSP &unix_signals_sp) +ProcessFreeBSD::ProcessFreeBSD(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + UnixSignalsSP &unix_signals_sp) : Process(target_sp, listener_sp, unix_signals_sp), - m_byte_order(endian::InlHostByteOrder()), - m_monitor(NULL), - m_module(NULL), - m_message_mutex(), - m_exit_now(false), - m_seen_initial_stop(), - m_resume_signo(0) -{ - // FIXME: Putting this code in the ctor and saving the byte order in a - // member variable is a hack to avoid const qual issues in GetByteOrder. - lldb::ModuleSP module = GetTarget().GetExecutableModule(); - if (module && module->GetObjectFile()) - m_byte_order = module->GetObjectFile()->GetByteOrder(); + m_byte_order(endian::InlHostByteOrder()), m_monitor(NULL), m_module(NULL), + m_message_mutex(), m_exit_now(false), m_seen_initial_stop(), + m_resume_signo(0) { + // FIXME: Putting this code in the ctor and saving the byte order in a + // member variable is a hack to avoid const qual issues in GetByteOrder. + lldb::ModuleSP module = GetTarget().GetExecutableModule(); + if (module && module->GetObjectFile()) + m_byte_order = module->GetObjectFile()->GetByteOrder(); } -ProcessFreeBSD::~ProcessFreeBSD() -{ - delete m_monitor; -} +ProcessFreeBSD::~ProcessFreeBSD() { delete m_monitor; } //------------------------------------------------------------------------------ // Process protocol. -void -ProcessFreeBSD::Finalize() -{ +void ProcessFreeBSD::Finalize() { Process::Finalize(); if (m_monitor) m_monitor->StopMonitor(); } -bool -ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) -{ - // For now we are just making sure the file exists for a given module - ModuleSP exe_module_sp(target_sp->GetExecutableModule()); - if (exe_module_sp.get()) - return exe_module_sp->GetFileSpec().Exists(); - // If there is no executable module, we return true since we might be preparing to attach. - return true; +bool ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + // For now we are just making sure the file exists for a given module + ModuleSP exe_module_sp(target_sp->GetExecutableModule()); + if (exe_module_sp.get()) + return exe_module_sp->GetFileSpec().Exists(); + // If there is no executable module, we return true since we might be + // preparing to attach. + return true; } -Error -ProcessFreeBSD::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) -{ - Error error; - assert(m_monitor == NULL); +Error ProcessFreeBSD::DoAttachToProcessWithID( + lldb::pid_t pid, const ProcessAttachInfo &attach_info) { + Error error; + assert(m_monitor == NULL); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessFreeBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID()); + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf("ProcessFreeBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID()); - m_monitor = new ProcessMonitor(this, pid, error); + m_monitor = new ProcessMonitor(this, pid, error); - if (!error.Success()) - return error; + if (!error.Success()) + return error; - PlatformSP platform_sp (GetTarget().GetPlatform ()); - assert (platform_sp.get()); - if (!platform_sp) - return error; // FIXME: Detatch? - - // Find out what we can about this process - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo (pid, process_info); - - // Resolve the executable module - ModuleSP exe_module_sp; - FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), GetTarget().GetArchitecture()); - error = platform_sp->ResolveExecutable(exe_module_spec, - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return error; + PlatformSP platform_sp(GetTarget().GetPlatform()); + assert(platform_sp.get()); + if (!platform_sp) + return error; // FIXME: Detatch? + + // Find out what we can about this process + ProcessInstanceInfo process_info; + platform_sp->GetProcessInfo(pid, process_info); + + // Resolve the executable module + ModuleSP exe_module_sp; + FileSpecList executable_search_paths( + Target::GetDefaultExecutableSearchPaths()); + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), + GetTarget().GetArchitecture()); + error = platform_sp->ResolveExecutable( + exe_module_spec, exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); + if (!error.Success()) + return error; - // Fix the target architecture if necessary - const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); - if (module_arch.IsValid() && !GetTarget().GetArchitecture().IsExactMatch(module_arch)) - GetTarget().SetArchitecture(module_arch); + // Fix the target architecture if necessary + const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); + if (module_arch.IsValid() && + !GetTarget().GetArchitecture().IsExactMatch(module_arch)) + GetTarget().SetArchitecture(module_arch); - // Initialize the target module list - GetTarget().SetExecutableModule (exe_module_sp, true); + // Initialize the target module list + GetTarget().SetExecutableModule(exe_module_sp, true); - SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); + SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); - SetID(pid); + SetID(pid); - return error; + return error; } -Error -ProcessFreeBSD::WillLaunch(Module* module) -{ - Error error; - return error; +Error ProcessFreeBSD::WillLaunch(Module *module) { + Error error; + return error; } FileSpec ProcessFreeBSD::GetFileSpec(const lldb_private::FileAction *file_action, - const FileSpec &default_file_spec, - const FileSpec &dbg_pts_file_spec) -{ - FileSpec file_spec{}; - - if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) - { - file_spec = file_action->GetFileSpec(); - // By default the stdio paths passed in will be pseudo-terminal - // (/dev/pts). If so, convert to using a different default path - // instead to redirect I/O to the debugger console. This should - // also handle user overrides to /dev/null or a different file. - if (!file_spec || file_spec == dbg_pts_file_spec) - file_spec = default_file_spec; - } - return file_spec; -} - -Error -ProcessFreeBSD::DoLaunch (Module *module, - ProcessLaunchInfo &launch_info) -{ - Error error; - assert(m_monitor == NULL); - - 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; - } + const FileSpec &default_file_spec, + const FileSpec &dbg_pts_file_spec) { + FileSpec file_spec{}; + + if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) { + file_spec = file_action->GetFileSpec(); + // By default the stdio paths passed in will be pseudo-terminal + // (/dev/pts). If so, convert to using a different default path + // instead to redirect I/O to the debugger console. This should + // also handle user overrides to /dev/null or a different file. + if (!file_spec || file_spec == dbg_pts_file_spec) + file_spec = default_file_spec; + } + return file_spec; +} + +Error ProcessFreeBSD::DoLaunch(Module *module, ProcessLaunchInfo &launch_info) { + Error error; + assert(m_monitor == NULL); + + 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; + } - SetPrivateState(eStateLaunching); + SetPrivateState(eStateLaunching); - const lldb_private::FileAction *file_action; + const lldb_private::FileAction *file_action; - // Default of empty will mean to use existing open file descriptors - FileSpec stdin_file_spec{}; - FileSpec stdout_file_spec{}; - FileSpec stderr_file_spec{}; + // Default of empty will mean to use existing open file descriptors + FileSpec stdin_file_spec{}; + FileSpec stdout_file_spec{}; + FileSpec stderr_file_spec{}; - const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; + const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL, 0), + false}; - file_action = launch_info.GetFileActionForFD (STDIN_FILENO); - stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); + file_action = launch_info.GetFileActionForFD(STDIN_FILENO); + stdin_file_spec = + GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); - file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); + file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); + stdout_file_spec = + GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); - file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); + file_action = launch_info.GetFileActionForFD(STDERR_FILENO); + stderr_file_spec = + GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); - m_monitor = new ProcessMonitor(this, - module, - launch_info.GetArguments().GetConstArgumentVector(), - launch_info.GetEnvironmentEntries().GetConstArgumentVector(), - stdin_file_spec, - stdout_file_spec, - stderr_file_spec, - working_dir, - launch_info, - error); + m_monitor = new ProcessMonitor( + this, module, launch_info.GetArguments().GetConstArgumentVector(), + launch_info.GetEnvironmentEntries().GetConstArgumentVector(), + stdin_file_spec, stdout_file_spec, stderr_file_spec, working_dir, + launch_info, error); - m_module = module; + m_module = module; - if (!error.Success()) - return error; + if (!error.Success()) + return error; - int terminal = m_monitor->GetTerminalFD(); - if (terminal >= 0) { - // The reader thread will close the file descriptor when done, so we pass it a copy. + int terminal = m_monitor->GetTerminalFD(); + if (terminal >= 0) { +// The reader thread will close the file descriptor when done, so we pass it a +// copy. #ifdef F_DUPFD_CLOEXEC - int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } + int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); + if (stdio == -1) { + error.SetErrorToErrno(); + return error; + } #else - // Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD) - int stdio = fcntl(terminal, F_DUPFD, 0); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } - stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC); - if (stdio == -1) { - error.SetErrorToErrno(); - return error; - } -#endif - SetSTDIOFileDescriptor(stdio); + // Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD) + int stdio = fcntl(terminal, F_DUPFD, 0); + if (stdio == -1) { + error.SetErrorToErrno(); + return error; + } + stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC); + if (stdio == -1) { + error.SetErrorToErrno(); + return error; } +#endif + SetSTDIOFileDescriptor(stdio); + } - SetID(m_monitor->GetPID()); - return error; + SetID(m_monitor->GetPID()); + return error; } -void -ProcessFreeBSD::DidLaunch() -{ -} +void ProcessFreeBSD::DidLaunch() {} -addr_t -ProcessFreeBSD::GetImageInfoAddress() -{ - Target *target = &GetTarget(); - ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(target); +addr_t ProcessFreeBSD::GetImageInfoAddress() { + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(target); - if (addr.IsValid()) - return addr.GetLoadAddress(target); - return LLDB_INVALID_ADDRESS; + if (addr.IsValid()) + return addr.GetLoadAddress(target); + return LLDB_INVALID_ADDRESS; } -Error -ProcessFreeBSD::DoHalt(bool &caused_stop) -{ - Error error; +Error ProcessFreeBSD::DoHalt(bool &caused_stop) { + Error error; - if (IsStopped()) - { - caused_stop = false; - } - else if (kill(GetID(), SIGSTOP)) - { - caused_stop = false; - error.SetErrorToErrno(); - } - else - { - caused_stop = true; - } - return error; + if (IsStopped()) { + caused_stop = false; + } else if (kill(GetID(), SIGSTOP)) { + caused_stop = false; + error.SetErrorToErrno(); + } else { + caused_stop = true; + } + return error; } -Error -ProcessFreeBSD::DoSignal(int signal) -{ - Error error; +Error ProcessFreeBSD::DoSignal(int signal) { + Error error; - if (kill(GetID(), signal)) - error.SetErrorToErrno(); + if (kill(GetID(), signal)) + error.SetErrorToErrno(); - return error; + return error; } -Error -ProcessFreeBSD::DoDestroy() -{ - Error error; - - if (!HasExited()) - { - assert(m_monitor); - m_exit_now = true; - if (GetID() == LLDB_INVALID_PROCESS_ID) - { - error.SetErrorString("invalid process id"); - return error; - } - if (!m_monitor->Kill()) - { - error.SetErrorToErrno(); - return error; - } - - SetPrivateState(eStateExited); - } +Error ProcessFreeBSD::DoDestroy() { + Error error; - return error; -} + if (!HasExited()) { + assert(m_monitor); + m_exit_now = true; + if (GetID() == LLDB_INVALID_PROCESS_ID) { + error.SetErrorString("invalid process id"); + return error; + } + if (!m_monitor->Kill()) { + error.SetErrorToErrno(); + return error; + } -void -ProcessFreeBSD::DoDidExec() -{ - Target *target = &GetTarget(); - if (target) - { - PlatformSP platform_sp (target->GetPlatform()); - assert (platform_sp.get()); - if (platform_sp) - { - ProcessInstanceInfo process_info; - platform_sp->GetProcessInfo(GetID(), process_info); - ModuleSP exe_module_sp; - ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture()); - FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - Error error = platform_sp->ResolveExecutable(exe_module_spec, - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : NULL); - if (!error.Success()) - return; - target->SetExecutableModule(exe_module_sp, true); - } + SetPrivateState(eStateExited); + } + + return error; +} + +void ProcessFreeBSD::DoDidExec() { + Target *target = &GetTarget(); + if (target) { + PlatformSP platform_sp(target->GetPlatform()); + assert(platform_sp.get()); + if (platform_sp) { + ProcessInstanceInfo process_info; + platform_sp->GetProcessInfo(GetID(), process_info); + ModuleSP exe_module_sp; + ModuleSpec exe_module_spec(process_info.GetExecutableFile(), + target->GetArchitecture()); + FileSpecList executable_search_paths( + Target::GetDefaultExecutableSearchPaths()); + Error error = platform_sp->ResolveExecutable( + exe_module_spec, exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); + if (!error.Success()) + return; + target->SetExecutableModule(exe_module_sp, true); } + } } -bool -ProcessFreeBSD::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) -{ - bool added_to_set = false; - ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); - if (it == m_seen_initial_stop.end()) - { - m_seen_initial_stop.insert(stop_tid); - added_to_set = true; - } - return added_to_set; +bool ProcessFreeBSD::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) { + bool added_to_set = false; + ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); + if (it == m_seen_initial_stop.end()) { + m_seen_initial_stop.insert(stop_tid); + added_to_set = true; + } + return added_to_set; } -bool -ProcessFreeBSD::WaitingForInitialStop(lldb::tid_t stop_tid) -{ - return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); +bool ProcessFreeBSD::WaitingForInitialStop(lldb::tid_t stop_tid) { + return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); } FreeBSDThread * -ProcessFreeBSD::CreateNewFreeBSDThread(lldb_private::Process &process, lldb::tid_t tid) -{ - return new FreeBSDThread(process, tid); +ProcessFreeBSD::CreateNewFreeBSDThread(lldb_private::Process &process, + lldb::tid_t tid) { + return new FreeBSDThread(process, tid); } -void -ProcessFreeBSD::RefreshStateAfterStop() -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) - log->Printf ("ProcessFreeBSD::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); - - std::lock_guard<std::recursive_mutex> guard(m_message_mutex); +void ProcessFreeBSD::RefreshStateAfterStop() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf("ProcessFreeBSD::%s(), message_queue size = %d", __FUNCTION__, + (int)m_message_queue.size()); - // This method used to only handle one message. Changing it to loop allows - // it to handle the case where we hit a breakpoint while handling a different - // breakpoint. - while (!m_message_queue.empty()) - { - ProcessMessage &message = m_message_queue.front(); + std::lock_guard<std::recursive_mutex> guard(m_message_mutex); - // Resolve the thread this message corresponds to and pass it along. - lldb::tid_t tid = message.GetTID(); - if (log) - log->Printf ("ProcessFreeBSD::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); + // This method used to only handle one message. Changing it to loop allows + // it to handle the case where we hit a breakpoint while handling a different + // breakpoint. + while (!m_message_queue.empty()) { + ProcessMessage &message = m_message_queue.front(); - m_thread_list.RefreshStateAfterStop(); + // Resolve the thread this message corresponds to and pass it along. + lldb::tid_t tid = message.GetTID(); + if (log) + log->Printf( + "ProcessFreeBSD::%s(), message_queue size = %d, pid = %" PRIi64, + __FUNCTION__, (int)m_message_queue.size(), tid); - FreeBSDThread *thread = static_cast<FreeBSDThread*>( - GetThreadList().FindThreadByID(tid, false).get()); - if (thread) - thread->Notify(message); + m_thread_list.RefreshStateAfterStop(); - if (message.GetKind() == ProcessMessage::eExitMessage) - { - // FIXME: We should tell the user about this, but the limbo message is probably better for that. - if (log) - log->Printf ("ProcessFreeBSD::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); + FreeBSDThread *thread = static_cast<FreeBSDThread *>( + GetThreadList().FindThreadByID(tid, false).get()); + if (thread) + thread->Notify(message); - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + if (message.GetKind() == ProcessMessage::eExitMessage) { + // FIXME: We should tell the user about this, but the limbo message is + // probably better for that. + if (log) + log->Printf("ProcessFreeBSD::%s() removing thread, tid = %" PRIi64, + __FUNCTION__, tid); - ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); - thread_sp.reset(); - m_seen_initial_stop.erase(tid); - } + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - m_message_queue.pop(); + ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); + thread_sp.reset(); + m_seen_initial_stop.erase(tid); } + + m_message_queue.pop(); + } } -bool -ProcessFreeBSD::IsAlive() -{ - StateType state = GetPrivateState(); - return state != eStateDetached - && state != eStateExited - && state != eStateInvalid - && state != eStateUnloaded; +bool ProcessFreeBSD::IsAlive() { + StateType state = GetPrivateState(); + return state != eStateDetached && state != eStateExited && + state != eStateInvalid && state != eStateUnloaded; } -size_t -ProcessFreeBSD::DoReadMemory(addr_t vm_addr, - void *buf, size_t size, Error &error) -{ - assert(m_monitor); - return m_monitor->ReadMemory(vm_addr, buf, size, error); +size_t ProcessFreeBSD::DoReadMemory(addr_t vm_addr, void *buf, size_t size, + Error &error) { + assert(m_monitor); + return m_monitor->ReadMemory(vm_addr, buf, size, error); } -size_t -ProcessFreeBSD::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size, - Error &error) -{ - assert(m_monitor); - return m_monitor->WriteMemory(vm_addr, buf, size, error); +size_t ProcessFreeBSD::DoWriteMemory(addr_t vm_addr, const void *buf, + size_t size, Error &error) { + assert(m_monitor); + return m_monitor->WriteMemory(vm_addr, buf, size, error); } -addr_t -ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions, - Error &error) -{ - addr_t allocated_addr = LLDB_INVALID_ADDRESS; - - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - if (InferiorCallMmap(this, allocated_addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { - m_addr_to_mmap_size[allocated_addr] = size; - error.Clear(); - } else { - allocated_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); - } +addr_t ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) { + addr_t allocated_addr = LLDB_INVALID_ADDRESS; + + unsigned prot = 0; + if (permissions & lldb::ePermissionsReadable) + prot |= eMmapProtRead; + if (permissions & lldb::ePermissionsWritable) + prot |= eMmapProtWrite; + if (permissions & lldb::ePermissionsExecutable) + prot |= eMmapProtExec; - return allocated_addr; + if (InferiorCallMmap(this, allocated_addr, 0, size, prot, + eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { + m_addr_to_mmap_size[allocated_addr] = size; + error.Clear(); + } else { + allocated_addr = LLDB_INVALID_ADDRESS; + error.SetErrorStringWithFormat( + "unable to allocate %zu bytes of memory with permissions %s", size, + GetPermissionsAsCString(permissions)); + } + + return allocated_addr; } -Error -ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) -{ - Error error; - MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); - if (pos != m_addr_to_mmap_size.end() && - InferiorCallMunmap(this, addr, pos->second)) - m_addr_to_mmap_size.erase (pos); - else - error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); +Error ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) { + Error error; + MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); + if (pos != m_addr_to_mmap_size.end() && + InferiorCallMunmap(this, addr, pos->second)) + m_addr_to_mmap_size.erase(pos); + else + error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, + addr); - return error; + return error; } size_t -ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) -{ - static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; - static const uint8_t g_i386_opcode[] = { 0xCC }; - - ArchSpec arch = GetTarget().GetArchitecture(); - const uint8_t *opcode = NULL; - size_t opcode_size = 0; - - switch (arch.GetMachine()) - { - default: - assert(false && "CPU type not supported!"); - break; - - case llvm::Triple::arm: - { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe - // but the linux kernel does otherwise. - static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; - static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; - - lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); - AddressClass addr_class = eAddressClassUnknown; - - if (bp_loc_sp) - addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); - - if (addr_class == eAddressClassCodeAlternateISA - || (addr_class == eAddressClassUnknown - && bp_loc_sp->GetAddress().GetOffset() & 1)) - { - opcode = g_thumb_breakpoint_opcode; - opcode_size = sizeof(g_thumb_breakpoint_opcode); - } - else - { - opcode = g_arm_breakpoint_opcode; - opcode_size = sizeof(g_arm_breakpoint_opcode); - } - } - break; - case llvm::Triple::aarch64: - opcode = g_aarch64_opcode; - opcode_size = sizeof(g_aarch64_opcode); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - opcode = g_i386_opcode; - opcode_size = sizeof(g_i386_opcode); - break; +ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) { + static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xD4}; + static const uint8_t g_i386_opcode[] = {0xCC}; + + ArchSpec arch = GetTarget().GetArchitecture(); + const uint8_t *opcode = NULL; + size_t opcode_size = 0; + + switch (arch.GetMachine()) { + default: + assert(false && "CPU type not supported!"); + break; + + case llvm::Triple::arm: { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe + // but the linux kernel does otherwise. + static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; + + lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); + AddressClass addr_class = eAddressClassUnknown; + + if (bp_loc_sp) + addr_class = bp_loc_sp->GetAddress().GetAddressClass(); + + if (addr_class == eAddressClassCodeAlternateISA || + (addr_class == eAddressClassUnknown && + bp_loc_sp->GetAddress().GetOffset() & 1)) { + opcode = g_thumb_breakpoint_opcode; + opcode_size = sizeof(g_thumb_breakpoint_opcode); + } else { + opcode = g_arm_breakpoint_opcode; + opcode_size = sizeof(g_arm_breakpoint_opcode); } + } break; + case llvm::Triple::aarch64: + opcode = g_aarch64_opcode; + opcode_size = sizeof(g_aarch64_opcode); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + opcode = g_i386_opcode; + opcode_size = sizeof(g_i386_opcode); + break; + } - bp_site->SetTrapOpcode(opcode, opcode_size); - return opcode_size; + bp_site->SetTrapOpcode(opcode, opcode_size); + return opcode_size; } -Error -ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) -{ - return EnableSoftwareBreakpoint(bp_site); +Error ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) { + return EnableSoftwareBreakpoint(bp_site); } -Error -ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) -{ - return DisableSoftwareBreakpoint(bp_site); +Error ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) { + return DisableSoftwareBreakpoint(bp_site); } -Error -ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (log) - log->Printf ("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (wp->IsEnabled()) - { - if (log) - log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", - watchID, (uint64_t)addr); - return error; - } - - // Try to find a vacant watchpoint slot in the inferiors' main thread - uint32_t wp_hw_index = LLDB_INVALID_INDEX32; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - FreeBSDThread *thread = static_cast<FreeBSDThread*>( - m_thread_list.GetThreadAtIndex(0, false).get()); +Error ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (wp->IsEnabled()) { + if (log) + log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", + watchID, (uint64_t)addr); + return error; + } - if (thread) - wp_hw_index = thread->FindVacantWatchpointIndex(); + // Try to find a vacant watchpoint slot in the inferiors' main thread + uint32_t wp_hw_index = LLDB_INVALID_INDEX32; + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + FreeBSDThread *thread = static_cast<FreeBSDThread *>( + m_thread_list.GetThreadAtIndex(0, false).get()); + + if (thread) + wp_hw_index = thread->FindVacantWatchpointIndex(); - if (wp_hw_index == LLDB_INVALID_INDEX32) - { - error.SetErrorString("Setting hardware watchpoint failed."); - } + if (wp_hw_index == LLDB_INVALID_INDEX32) { + error.SetErrorString("Setting hardware watchpoint failed."); + } else { + wp->SetHardwareIndex(wp_hw_index); + bool wp_enabled = true; + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) { + thread = static_cast<FreeBSDThread *>( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_enabled &= thread->EnableHardwareWatchpoint(wp); else - { - wp->SetHardwareIndex(wp_hw_index); - bool wp_enabled = true; - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - thread = static_cast<FreeBSDThread*>( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_enabled &= thread->EnableHardwareWatchpoint(wp); - else - wp_enabled = false; - } - if (wp_enabled) - { - wp->SetEnabled(true, notify); - return error; - } - else - { - // Watchpoint enabling failed on at least one - // of the threads so roll back all of them - DisableWatchpoint(wp, false); - error.SetErrorString("Setting hardware watchpoint failed"); - } - } + wp_enabled = false; + } + if (wp_enabled) { + wp->SetEnabled(true, notify); + return error; + } else { + // Watchpoint enabling failed on at least one + // of the threads so roll back all of them + DisableWatchpoint(wp, false); + error.SetErrorString("Setting hardware watchpoint failed"); + } } - else - error.SetErrorString("Watchpoint argument was NULL."); - return error; + } else + error.SetErrorString("Watchpoint argument was NULL."); + return error; } -Error -ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) -{ - Error error; - if (wp) - { - user_id_t watchID = wp->GetID(); - addr_t addr = wp->GetLoadAddress(); - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (log) - log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ")", - watchID); - if (!wp->IsEnabled()) - { - if (log) - log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 - ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", - watchID, (uint64_t)addr); - // This is needed (for now) to keep watchpoints disabled correctly - wp->SetEnabled(false, notify); - return error; - } - - if (wp->IsHardware()) - { - bool wp_disabled = true; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - FreeBSDThread *thread = static_cast<FreeBSDThread*>( - m_thread_list.GetThreadAtIndex(i, false).get()); - if (thread) - wp_disabled &= thread->DisableHardwareWatchpoint(wp); - else - wp_disabled = false; - } - if (wp_disabled) - { - wp->SetHardwareIndex(LLDB_INVALID_INDEX32); - wp->SetEnabled(false, notify); - return error; - } - else - error.SetErrorString("Disabling hardware watchpoint failed"); - } +Error ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + if (wp) { + user_id_t watchID = wp->GetID(); + addr_t addr = wp->GetLoadAddress(); + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + if (log) + log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ")", + watchID); + if (!wp->IsEnabled()) { + if (log) + log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 + ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", + watchID, (uint64_t)addr); + // This is needed (for now) to keep watchpoints disabled correctly + wp->SetEnabled(false, notify); + return error; } - else - error.SetErrorString("Watchpoint argument was NULL."); - return error; + + if (wp->IsHardware()) { + bool wp_disabled = true; + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) { + FreeBSDThread *thread = static_cast<FreeBSDThread *>( + m_thread_list.GetThreadAtIndex(i, false).get()); + if (thread) + wp_disabled &= thread->DisableHardwareWatchpoint(wp); + else + wp_disabled = false; + } + if (wp_disabled) { + wp->SetHardwareIndex(LLDB_INVALID_INDEX32); + wp->SetEnabled(false, notify); + return error; + } else + error.SetErrorString("Disabling hardware watchpoint failed"); + } + } else + error.SetErrorString("Watchpoint argument was NULL."); + return error; } -Error -ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) -{ - Error error; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - FreeBSDThread *thread = static_cast<FreeBSDThread*>( - m_thread_list.GetThreadAtIndex(0, false).get()); - if (thread) - num = thread->NumSupportedHardwareWatchpoints(); - else - error.SetErrorString("Process does not exist."); - return error; +Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) { + Error error; + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + FreeBSDThread *thread = static_cast<FreeBSDThread *>( + m_thread_list.GetThreadAtIndex(0, false).get()); + if (thread) + num = thread->NumSupportedHardwareWatchpoints(); + else + error.SetErrorString("Process does not exist."); + return error; } -Error -ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) -{ - Error error = GetWatchpointSupportInfo(num); - // Watchpoints trigger and halt the inferior after - // the corresponding instruction has been executed. - after = true; - return error; +Error ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) { + Error error = GetWatchpointSupportInfo(num); + // Watchpoints trigger and halt the inferior after + // the corresponding instruction has been executed. + after = true; + return error; } -uint32_t -ProcessFreeBSD::UpdateThreadListIfNeeded() -{ - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - // Do not allow recursive updates. - return m_thread_list.GetSize(false); +uint32_t ProcessFreeBSD::UpdateThreadListIfNeeded() { + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + // Do not allow recursive updates. + return m_thread_list.GetSize(false); } #if 0 @@ -955,91 +839,77 @@ ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_th } #endif -ByteOrder -ProcessFreeBSD::GetByteOrder() const -{ - // FIXME: We should be able to extract this value directly. See comment in - // ProcessFreeBSD(). - return m_byte_order; +ByteOrder ProcessFreeBSD::GetByteOrder() const { + // FIXME: We should be able to extract this value directly. See comment in + // ProcessFreeBSD(). + return m_byte_order; } -size_t -ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Error &error) -{ - ssize_t status; - if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) - { - error.SetErrorToErrno(); - return 0; - } - return status; +size_t ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Error &error) { + ssize_t status; + if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) { + error.SetErrorToErrno(); + return 0; + } + return status; } //------------------------------------------------------------------------------ // Utility functions. -bool -ProcessFreeBSD::HasExited() -{ - switch (GetPrivateState()) - { - default: - break; - - case eStateDetached: - case eStateExited: - return true; - } - - return false; -} +bool ProcessFreeBSD::HasExited() { + switch (GetPrivateState()) { + default: + break; -bool -ProcessFreeBSD::IsStopped() -{ - switch (GetPrivateState()) - { - default: - break; - - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - return true; - } + case eStateDetached: + case eStateExited: + return true; + } - return false; + return false; } -bool -ProcessFreeBSD::IsAThreadRunning() -{ - bool is_running = false; - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - FreeBSDThread *thread = static_cast<FreeBSDThread*>( - m_thread_list.GetThreadAtIndex(i, false).get()); - StateType thread_state = thread->GetState(); - if (thread_state == eStateRunning || thread_state == eStateStepping) - { - is_running = true; - break; - } - } - return is_running; -} +bool ProcessFreeBSD::IsStopped() { + switch (GetPrivateState()) { + default: + break; -const DataBufferSP -ProcessFreeBSD::GetAuxvData () -{ - // If we're the local platform, we can ask the host for auxv data. - PlatformSP platform_sp = GetTarget().GetPlatform (); - if (platform_sp && platform_sp->IsHost ()) - return lldb_private::Host::GetAuxvData(this); - - // Somewhat unexpected - the process is not running locally or we don't have a platform. - assert (false && "no platform or not the host - how did we get here with ProcessFreeBSD?"); - return DataBufferSP (); + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + return true; + } + + return false; +} + +bool ProcessFreeBSD::IsAThreadRunning() { + bool is_running = false; + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) { + FreeBSDThread *thread = static_cast<FreeBSDThread *>( + m_thread_list.GetThreadAtIndex(i, false).get()); + StateType thread_state = thread->GetState(); + if (thread_state == eStateRunning || thread_state == eStateStepping) { + is_running = true; + break; + } + } + return is_running; +} + +const DataBufferSP ProcessFreeBSD::GetAuxvData() { + // If we're the local platform, we can ask the host for auxv data. + PlatformSP platform_sp = GetTarget().GetPlatform(); + if (platform_sp && platform_sp->IsHost()) + return lldb_private::Host::GetAuxvData(this); + + // Somewhat unexpected - the process is not running locally or we don't have a + // platform. + assert( + false && + "no platform or not the host - how did we get here with ProcessFreeBSD?"); + return DataBufferSP(); } diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h index 888e2a90ad76..cd38989f973c 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h @@ -1,4 +1,5 @@ -//===-- ProcessFreeBSD.h ------------------------------------------*- C++ -*-===// +//===-- ProcessFreeBSD.h ------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -18,233 +19,200 @@ #include <set> // Other libraries and framework includes +#include "ProcessFreeBSD.h" +#include "ProcessMessage.h" #include "lldb/Target/Process.h" #include "lldb/Target/ThreadList.h" -#include "ProcessMessage.h" -#include "ProcessFreeBSD.h" class ProcessMonitor; class FreeBSDThread; -class ProcessFreeBSD : - public lldb_private::Process -{ +class ProcessFreeBSD : public lldb_private::Process { public: - //------------------------------------------------------------------ - // Static functions. - //------------------------------------------------------------------ - static lldb::ProcessSP - CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); + //------------------------------------------------------------------ + // Static functions. + //------------------------------------------------------------------ + static lldb::ProcessSP + CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const lldb_private::FileSpec *crash_file_path); - static void - Initialize(); + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessFreeBSD(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - lldb::UnixSignalsSP &unix_signals_sp); + //------------------------------------------------------------------ + // Constructors and destructors + //------------------------------------------------------------------ + ProcessFreeBSD(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + lldb::UnixSignalsSP &unix_signals_sp); - ~ProcessFreeBSD(); + ~ProcessFreeBSD(); - virtual lldb_private::Error - WillResume() override; + virtual lldb_private::Error WillResume() override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - virtual lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString GetPluginName() override; - virtual uint32_t - GetPluginVersion() override; + virtual uint32_t GetPluginVersion() override; public: - //------------------------------------------------------------------ - // Process protocol. - //------------------------------------------------------------------ - void - Finalize() override; + //------------------------------------------------------------------ + // Process protocol. + //------------------------------------------------------------------ + void Finalize() override; - bool - CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; - lldb_private::Error - WillLaunch(lldb_private::Module *module) override; + lldb_private::Error WillLaunch(lldb_private::Module *module) override; - lldb_private::Error - DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override; + lldb_private::Error DoAttachToProcessWithID( + lldb::pid_t pid, + const lldb_private::ProcessAttachInfo &attach_info) override; - lldb_private::Error - DoLaunch (lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info) override; + lldb_private::Error + DoLaunch(lldb_private::Module *exe_module, + lldb_private::ProcessLaunchInfo &launch_info) override; - void - DidLaunch() override; + void DidLaunch() override; - lldb_private::Error - DoResume() override; + lldb_private::Error DoResume() override; - lldb_private::Error - DoHalt(bool &caused_stop) override; + lldb_private::Error DoHalt(bool &caused_stop) override; - lldb_private::Error - DoDetach(bool keep_stopped) override; + lldb_private::Error DoDetach(bool keep_stopped) override; - lldb_private::Error - DoSignal(int signal) override; + lldb_private::Error DoSignal(int signal) override; - lldb_private::Error - DoDestroy() override; + lldb_private::Error DoDestroy() override; - void - DoDidExec() override; + void DoDidExec() override; - void - RefreshStateAfterStop() override; + void RefreshStateAfterStop() override; - bool - IsAlive() override; + bool IsAlive() override; - size_t - DoReadMemory(lldb::addr_t vm_addr, - void *buf, - size_t size, - lldb_private::Error &error) override; + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + lldb_private::Error &error) override; - size_t - DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error) override; + size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, + lldb_private::Error &error) override; - lldb::addr_t - DoAllocateMemory(size_t size, uint32_t permissions, - lldb_private::Error &error) override; + lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, + lldb_private::Error &error) override; - lldb_private::Error - DoDeallocateMemory(lldb::addr_t ptr) override; + lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr) override; - virtual size_t - GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); + virtual size_t + GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite *bp_site); - lldb_private::Error - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + lldb_private::Error + EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - lldb_private::Error - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; + lldb_private::Error + DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - lldb_private::Error - EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; + lldb_private::Error EnableWatchpoint(lldb_private::Watchpoint *wp, + bool notify = true) override; - lldb_private::Error - DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override; + lldb_private::Error DisableWatchpoint(lldb_private::Watchpoint *wp, + bool notify = true) override; - lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num) override; + lldb_private::Error GetWatchpointSupportInfo(uint32_t &num) override; - lldb_private::Error - GetWatchpointSupportInfo(uint32_t &num, bool &after) override; + lldb_private::Error GetWatchpointSupportInfo(uint32_t &num, + bool &after) override; - virtual uint32_t - UpdateThreadListIfNeeded(); + virtual uint32_t UpdateThreadListIfNeeded(); - bool - UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; - virtual lldb::ByteOrder - GetByteOrder() const; + virtual lldb::ByteOrder GetByteOrder() const; - lldb::addr_t - GetImageInfoAddress() override; + lldb::addr_t GetImageInfoAddress() override; - size_t - PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override; + size_t PutSTDIN(const char *buf, size_t len, + lldb_private::Error &error) override; - const lldb::DataBufferSP - GetAuxvData () override; + const lldb::DataBufferSP GetAuxvData() override; - //-------------------------------------------------------------------------- - // ProcessFreeBSD internal API. + //-------------------------------------------------------------------------- + // ProcessFreeBSD internal API. - /// Registers the given message with this process. - virtual void - SendMessage(const ProcessMessage &message); + /// Registers the given message with this process. + virtual void SendMessage(const ProcessMessage &message); - ProcessMonitor & - GetMonitor() { assert(m_monitor); return *m_monitor; } + ProcessMonitor &GetMonitor() { + assert(m_monitor); + return *m_monitor; + } - lldb_private::FileSpec - GetFileSpec(const lldb_private::FileAction *file_action, - const lldb_private::FileSpec &default_file_spec, - const lldb_private::FileSpec &dbg_pts_file_spec); + lldb_private::FileSpec + GetFileSpec(const lldb_private::FileAction *file_action, + const lldb_private::FileSpec &default_file_spec, + const lldb_private::FileSpec &dbg_pts_file_spec); - /// Adds the thread to the list of threads for which we have received the initial stopping signal. - /// The \p stop_tid parameter indicates the thread which the stop happened for. - bool - AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); + /// Adds the thread to the list of threads for which we have received the + /// initial stopping signal. + /// The \p stop_tid parameter indicates the thread which the stop happened + /// for. + bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); - bool - WaitingForInitialStop(lldb::tid_t stop_tid); + bool WaitingForInitialStop(lldb::tid_t stop_tid); - virtual FreeBSDThread * - CreateNewFreeBSDThread(lldb_private::Process &process, lldb::tid_t tid); + virtual FreeBSDThread *CreateNewFreeBSDThread(lldb_private::Process &process, + lldb::tid_t tid); protected: - /// Target byte order. - lldb::ByteOrder m_byte_order; - - /// Process monitor; - ProcessMonitor *m_monitor; + /// Target byte order. + lldb::ByteOrder m_byte_order; - /// The module we are executing. - lldb_private::Module *m_module; + /// Process monitor; + ProcessMonitor *m_monitor; - /// Message queue notifying this instance of inferior process state changes. - std::recursive_mutex m_message_mutex; - std::queue<ProcessMessage> m_message_queue; + /// The module we are executing. + lldb_private::Module *m_module; - /// Drive any exit events to completion. - bool m_exit_now; + /// Message queue notifying this instance of inferior process state changes. + std::recursive_mutex m_message_mutex; + std::queue<ProcessMessage> m_message_queue; - /// Returns true if the process has exited. - bool HasExited(); + /// Drive any exit events to completion. + bool m_exit_now; - /// Returns true if the process is stopped. - bool IsStopped(); + /// Returns true if the process has exited. + bool HasExited(); - /// Returns true if at least one running is currently running - bool IsAThreadRunning(); + /// Returns true if the process is stopped. + bool IsStopped(); - typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; - MMapMap m_addr_to_mmap_size; + /// Returns true if at least one running is currently running + bool IsAThreadRunning(); - typedef std::set<lldb::tid_t> ThreadStopSet; - /// Every thread begins with a stop signal. This keeps track - /// of the threads for which we have received the stop signal. - ThreadStopSet m_seen_initial_stop; + typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap; + MMapMap m_addr_to_mmap_size; - friend class FreeBSDThread; + typedef std::set<lldb::tid_t> ThreadStopSet; + /// Every thread begins with a stop signal. This keeps track + /// of the threads for which we have received the stop signal. + ThreadStopSet m_seen_initial_stop; - typedef std::vector<lldb::tid_t> tid_collection; - tid_collection m_suspend_tids; - tid_collection m_run_tids; - tid_collection m_step_tids; + friend class FreeBSDThread; - int m_resume_signo; + typedef std::vector<lldb::tid_t> tid_collection; + tid_collection m_suspend_tids; + tid_collection m_run_tids; + tid_collection m_step_tids; + int m_resume_signo; }; -#endif // liblldb_ProcessFreeBSD_H_ +#endif // liblldb_ProcessFreeBSD_H_ diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 16707a5c8b97..afc649de3b65 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -10,14 +10,14 @@ // C Includes #include <errno.h> #include <poll.h> -#include <string.h> -#include <stdint.h> -#include <unistd.h> #include <signal.h> +#include <stdint.h> +#include <string.h> #include <sys/ptrace.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> // C++ Includes // Other libraries and framework includes @@ -26,20 +26,20 @@ #include "lldb/Core/Scalar.h" #include "lldb/Host/Host.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/PseudoTerminal.h" -#include "Plugins/Process/POSIX/CrashReason.h" #include "FreeBSDThread.h" +#include "Plugins/Process/POSIX/CrashReason.h" #include "ProcessFreeBSD.h" -#include "ProcessPOSIXLog.h" #include "ProcessMonitor.h" +#include "ProcessPOSIXLog.h" extern "C" { - extern char ** environ; - } +extern char **environ; +} using namespace lldb; using namespace lldb_private; @@ -49,96 +49,103 @@ using namespace lldb_private; #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION // Wrapper for ptrace to catch errors and log calls. -const char * -Get_PT_IO_OP(int op) -{ - switch (op) { - case PIOD_READ_D: return "READ_D"; - case PIOD_WRITE_D: return "WRITE_D"; - case PIOD_READ_I: return "READ_I"; - case PIOD_WRITE_I: return "WRITE_I"; - default: return "Unknown op"; - } +const char *Get_PT_IO_OP(int op) { + switch (op) { + case PIOD_READ_D: + return "READ_D"; + case PIOD_WRITE_D: + return "WRITE_D"; + case PIOD_READ_I: + return "READ_I"; + case PIOD_WRITE_I: + return "WRITE_I"; + default: + return "Unknown op"; + } } // Wrapper for ptrace to catch errors and log calls. -// Note that ptrace sets errno on error because -1 is reserved as a valid result. -extern long -PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, - const char* reqName, const char* file, int line) -{ - long int result; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - if (log) { - log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d", - reqName, pid, addr, data, file, line); - if (req == PT_IO) { - struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr; - - log->Printf("PT_IO: op=%s offs=%zx size=%zu", - Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len); - } +// Note that ptrace sets errno on error because -1 is reserved as a valid +// result. +extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, + const char *reqName, const char *file, int line) { + long int result; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + + if (log) { + log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d", + reqName, pid, addr, data, file, line); + if (req == PT_IO) { + struct ptrace_io_desc *pi = (struct ptrace_io_desc *)addr; + + log->Printf("PT_IO: op=%s offs=%zx size=%zu", Get_PT_IO_OP(pi->piod_op), + (size_t)pi->piod_offs, pi->piod_len); } - - //PtraceDisplayBytes(req, data); - - errno = 0; - result = ptrace(req, pid, (caddr_t) addr, data); - - //PtraceDisplayBytes(req, data); - - if (log && errno != 0) - { - const char* str; - switch (errno) - { - case ESRCH: str = "ESRCH"; break; - case EINVAL: str = "EINVAL"; break; - case EBUSY: str = "EBUSY"; break; - case EPERM: str = "EPERM"; break; - default: str = "<unknown>"; - } - log->Printf("ptrace() failed; errno=%d (%s)", errno, str); + } + + // PtraceDisplayBytes(req, data); + + errno = 0; + result = ptrace(req, pid, (caddr_t)addr, data); + + // PtraceDisplayBytes(req, data); + + if (log && errno != 0) { + const char *str; + switch (errno) { + case ESRCH: + str = "ESRCH"; + break; + case EINVAL: + str = "EINVAL"; + break; + case EBUSY: + str = "EBUSY"; + break; + case EPERM: + str = "EPERM"; + break; + default: + str = "<unknown>"; } + log->Printf("ptrace() failed; errno=%d (%s)", errno, str); + } - if (log) { + if (log) { #ifdef __amd64__ - if (req == PT_GETREGS) { - struct reg *r = (struct reg *) addr; - - log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx", - r->r_rip, r->r_rsp, r->r_rbp, r->r_rax); - } - if (req == PT_GETDBREGS || req == PT_SETDBREGS) { - struct dbreg *r = (struct dbreg *) addr; - char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; - - for (int i = 0; i <= 7; i++) - log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); - } -#endif + if (req == PT_GETREGS) { + struct reg *r = (struct reg *)addr; + + log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx", + r->r_rip, r->r_rsp, r->r_rbp, r->r_rax); } - - return result; + if (req == PT_GETDBREGS || req == PT_SETDBREGS) { + struct dbreg *r = (struct dbreg *)addr; + char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; + + for (int i = 0; i <= 7; i++) + log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); + } +#endif + } + + return result; } // Wrapper for ptrace when logging is not required. // Sets errno to 0 prior to calling ptrace. -extern long -PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) -{ - long result = 0; - errno = 0; - result = ptrace(req, pid, (caddr_t)addr, data); - return result; +extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) { + long result = 0; + errno = 0; + result = ptrace(req, pid, (caddr_t)addr, data); + return result; } -#define PTRACE(req, pid, addr, data) \ - PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__) +#define PTRACE(req, pid, addr, data) \ + PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__) #else - PtraceWrapper((req), (pid), (addr), (data)) +PtraceWrapper((req), (pid), (addr), (data)) #endif //------------------------------------------------------------------------------ @@ -146,58 +153,50 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) // ProcessMonitor::WriteMemory. This enables mutual recursion between these // functions without needed to go thru the thread funnel. -static size_t -DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, size_t size, - Error &error) -{ - struct ptrace_io_desc pi_desc; +static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, + size_t size, Error &error) { + struct ptrace_io_desc pi_desc; - pi_desc.piod_op = PIOD_READ_D; - pi_desc.piod_offs = (void *)vm_addr; - pi_desc.piod_addr = buf; - pi_desc.piod_len = size; + pi_desc.piod_op = PIOD_READ_D; + pi_desc.piod_offs = (void *)vm_addr; + pi_desc.piod_addr = buf; + pi_desc.piod_len = size; - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) - error.SetErrorToErrno(); - return pi_desc.piod_len; + if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) + error.SetErrorToErrno(); + return pi_desc.piod_len; } -static size_t -DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf, - size_t size, Error &error) -{ - struct ptrace_io_desc pi_desc; +static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, + const void *buf, size_t size, Error &error) { + struct ptrace_io_desc pi_desc; - pi_desc.piod_op = PIOD_WRITE_D; - pi_desc.piod_offs = (void *)vm_addr; - pi_desc.piod_addr = (void *)buf; - pi_desc.piod_len = size; + pi_desc.piod_op = PIOD_WRITE_D; + pi_desc.piod_offs = (void *)vm_addr; + pi_desc.piod_addr = (void *)buf; + pi_desc.piod_len = size; - if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) - error.SetErrorToErrno(); - return pi_desc.piod_len; + if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) + error.SetErrorToErrno(); + return pi_desc.piod_len; } // Simple helper function to ensure flags are enabled on the given file // descriptor. -static bool -EnsureFDFlags(int fd, int flags, Error &error) -{ - int status; - - if ((status = fcntl(fd, F_GETFL)) == -1) - { - error.SetErrorToErrno(); - return false; - } +static bool EnsureFDFlags(int fd, int flags, Error &error) { + int status; - if (fcntl(fd, F_SETFL, status | flags) == -1) - { - error.SetErrorToErrno(); - return false; - } + if ((status = fcntl(fd, F_GETFL)) == -1) { + error.SetErrorToErrno(); + return false; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return false; + } - return true; + return true; } //------------------------------------------------------------------------------ @@ -211,1383 +210,1216 @@ EnsureFDFlags(int fd, int flags, Error &error) /// task. The Operation class provides an abstract base for all services the /// ProcessMonitor must perform via the single virtual function Execute, thus /// encapsulating the code that needs to run in the privileged context. -class Operation -{ +class Operation { public: - virtual ~Operation() {} - virtual void Execute(ProcessMonitor *monitor) = 0; + virtual ~Operation() {} + virtual void Execute(ProcessMonitor *monitor) = 0; }; //------------------------------------------------------------------------------ /// @class ReadOperation /// @brief Implements ProcessMonitor::ReadMemory. -class ReadOperation : public Operation -{ +class ReadOperation : public Operation { public: - ReadOperation(lldb::addr_t addr, void *buff, size_t size, - Error &error, size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), - m_error(error), m_result(result) - { } + ReadOperation(lldb::addr_t addr, void *buff, size_t size, Error &error, + size_t &result) + : m_addr(addr), m_buff(buff), m_size(size), m_error(error), + m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::addr_t m_addr; - void *m_buff; - size_t m_size; - Error &m_error; - size_t &m_result; + lldb::addr_t m_addr; + void *m_buff; + size_t m_size; + Error &m_error; + size_t &m_result; }; -void -ReadOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); +void ReadOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); - m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error); + m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error); } //------------------------------------------------------------------------------ /// @class WriteOperation /// @brief Implements ProcessMonitor::WriteMemory. -class WriteOperation : public Operation -{ +class WriteOperation : public Operation { public: - WriteOperation(lldb::addr_t addr, const void *buff, size_t size, - Error &error, size_t &result) - : m_addr(addr), m_buff(buff), m_size(size), - m_error(error), m_result(result) - { } + WriteOperation(lldb::addr_t addr, const void *buff, size_t size, Error &error, + size_t &result) + : m_addr(addr), m_buff(buff), m_size(size), m_error(error), + m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::addr_t m_addr; - const void *m_buff; - size_t m_size; - Error &m_error; - size_t &m_result; + lldb::addr_t m_addr; + const void *m_buff; + size_t m_size; + Error &m_error; + size_t &m_result; }; -void -WriteOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); +void WriteOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); - m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error); + m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error); } //------------------------------------------------------------------------------ /// @class ReadRegOperation /// @brief Implements ProcessMonitor::ReadRegisterValue. -class ReadRegOperation : public Operation -{ +class ReadRegOperation : public Operation { public: - ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, - RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_size(size), - m_value(value), m_result(result) - { } + ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, + RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), m_size(size), m_value(value), + m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - unsigned m_offset; - unsigned m_size; - RegisterValue &m_value; - bool &m_result; + lldb::tid_t m_tid; + unsigned m_offset; + unsigned m_size; + RegisterValue &m_value; + bool &m_result; }; -void -ReadRegOperation::Execute(ProcessMonitor *monitor) -{ - struct reg regs; - int rc; - - if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0)) < 0) { - m_result = false; - } else { - // 'struct reg' contains only 32- or 64-bit register values. Punt on - // others. Also, not all entries may be uintptr_t sized, such as 32-bit - // processes on powerpc64 (probably the same for i386 on amd64) - if (m_size == sizeof(uint32_t)) - m_value = *(uint32_t *)(((caddr_t)®s) + m_offset); - else if (m_size == sizeof(uint64_t)) - m_value = *(uint64_t *)(((caddr_t)®s) + m_offset); - else - memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); - m_result = true; - } +void ReadRegOperation::Execute(ProcessMonitor *monitor) { + struct reg regs; + int rc; + + if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0)) < 0) { + m_result = false; + } else { + // 'struct reg' contains only 32- or 64-bit register values. Punt on + // others. Also, not all entries may be uintptr_t sized, such as 32-bit + // processes on powerpc64 (probably the same for i386 on amd64) + if (m_size == sizeof(uint32_t)) + m_value = *(uint32_t *)(((caddr_t)®s) + m_offset); + else if (m_size == sizeof(uint64_t)) + m_value = *(uint64_t *)(((caddr_t)®s) + m_offset); + else + memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); + m_result = true; + } } //------------------------------------------------------------------------------ /// @class WriteRegOperation /// @brief Implements ProcessMonitor::WriteRegisterValue. -class WriteRegOperation : public Operation -{ +class WriteRegOperation : public Operation { public: - WriteRegOperation(lldb::tid_t tid, unsigned offset, - const RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), - m_value(value), m_result(result) - { } + WriteRegOperation(lldb::tid_t tid, unsigned offset, + const RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), m_value(value), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - unsigned m_offset; - const RegisterValue &m_value; - bool &m_result; + lldb::tid_t m_tid; + unsigned m_offset; + const RegisterValue &m_value; + bool &m_result; }; -void -WriteRegOperation::Execute(ProcessMonitor *monitor) -{ - struct reg regs; +void WriteRegOperation::Execute(ProcessMonitor *monitor) { + struct reg regs; - if (PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0) < 0) { - m_result = false; - return; - } - *(uintptr_t *)(((caddr_t)®s) + m_offset) = (uintptr_t)m_value.GetAsUInt64(); - if (PTRACE(PT_SETREGS, m_tid, (caddr_t)®s, 0) < 0) - m_result = false; - else - m_result = true; + if (PTRACE(PT_GETREGS, m_tid, (caddr_t)®s, 0) < 0) { + m_result = false; + return; + } + *(uintptr_t *)(((caddr_t)®s) + m_offset) = + (uintptr_t)m_value.GetAsUInt64(); + if (PTRACE(PT_SETREGS, m_tid, (caddr_t)®s, 0) < 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class ReadDebugRegOperation /// @brief Implements ProcessMonitor::ReadDebugRegisterValue. -class ReadDebugRegOperation : public Operation -{ +class ReadDebugRegOperation : public Operation { public: - ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, - RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), m_size(size), - m_value(value), m_result(result) - { } + ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, + RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), m_size(size), m_value(value), + m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - unsigned m_offset; - unsigned m_size; - RegisterValue &m_value; - bool &m_result; + lldb::tid_t m_tid; + unsigned m_offset; + unsigned m_size; + RegisterValue &m_value; + bool &m_result; }; -void -ReadDebugRegOperation::Execute(ProcessMonitor *monitor) -{ - struct dbreg regs; - int rc; - - if ((rc = PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0)) < 0) { - m_result = false; - } else { - if (m_size == sizeof(uintptr_t)) - m_value = *(uintptr_t *)(((caddr_t)®s) + m_offset); - else - memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); - m_result = true; - } +void ReadDebugRegOperation::Execute(ProcessMonitor *monitor) { + struct dbreg regs; + int rc; + + if ((rc = PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0)) < 0) { + m_result = false; + } else { + if (m_size == sizeof(uintptr_t)) + m_value = *(uintptr_t *)(((caddr_t)®s) + m_offset); + else + memcpy((void *)&m_value, (((caddr_t)®s) + m_offset), m_size); + m_result = true; + } } //------------------------------------------------------------------------------ /// @class WriteDebugRegOperation /// @brief Implements ProcessMonitor::WriteDebugRegisterValue. -class WriteDebugRegOperation : public Operation -{ +class WriteDebugRegOperation : public Operation { public: - WriteDebugRegOperation(lldb::tid_t tid, unsigned offset, - const RegisterValue &value, bool &result) - : m_tid(tid), m_offset(offset), - m_value(value), m_result(result) - { } + WriteDebugRegOperation(lldb::tid_t tid, unsigned offset, + const RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), m_value(value), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - unsigned m_offset; - const RegisterValue &m_value; - bool &m_result; + lldb::tid_t m_tid; + unsigned m_offset; + const RegisterValue &m_value; + bool &m_result; }; -void -WriteDebugRegOperation::Execute(ProcessMonitor *monitor) -{ - struct dbreg regs; +void WriteDebugRegOperation::Execute(ProcessMonitor *monitor) { + struct dbreg regs; - if (PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0) < 0) { - m_result = false; - return; - } - *(uintptr_t *)(((caddr_t)®s) + m_offset) = (uintptr_t)m_value.GetAsUInt64(); - if (PTRACE(PT_SETDBREGS, m_tid, (caddr_t)®s, 0) < 0) - m_result = false; - else - m_result = true; + if (PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0) < 0) { + m_result = false; + return; + } + *(uintptr_t *)(((caddr_t)®s) + m_offset) = + (uintptr_t)m_value.GetAsUInt64(); + if (PTRACE(PT_SETDBREGS, m_tid, (caddr_t)®s, 0) < 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class ReadGPROperation /// @brief Implements ProcessMonitor::ReadGPR. -class ReadGPROperation : public Operation -{ +class ReadGPROperation : public Operation { public: - ReadGPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) - { } + ReadGPROperation(lldb::tid_t tid, void *buf, bool &result) + : m_tid(tid), m_buf(buf), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; + lldb::tid_t m_tid; + void *m_buf; + bool &m_result; }; -void -ReadGPROperation::Execute(ProcessMonitor *monitor) -{ - int rc; +void ReadGPROperation::Execute(ProcessMonitor *monitor) { + int rc; - errno = 0; - rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0); - if (errno != 0) - m_result = false; - else - m_result = true; + errno = 0; + rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0); + if (errno != 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class ReadFPROperation /// @brief Implements ProcessMonitor::ReadFPR. -class ReadFPROperation : public Operation -{ +class ReadFPROperation : public Operation { public: - ReadFPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) - { } + ReadFPROperation(lldb::tid_t tid, void *buf, bool &result) + : m_tid(tid), m_buf(buf), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; + lldb::tid_t m_tid; + void *m_buf; + bool &m_result; }; -void -ReadFPROperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; +void ReadFPROperation::Execute(ProcessMonitor *monitor) { + if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class WriteGPROperation /// @brief Implements ProcessMonitor::WriteGPR. -class WriteGPROperation : public Operation -{ +class WriteGPROperation : public Operation { public: - WriteGPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) - { } + WriteGPROperation(lldb::tid_t tid, void *buf, bool &result) + : m_tid(tid), m_buf(buf), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; + lldb::tid_t m_tid; + void *m_buf; + bool &m_result; }; -void -WriteGPROperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; +void WriteGPROperation::Execute(ProcessMonitor *monitor) { + if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class WriteFPROperation /// @brief Implements ProcessMonitor::WriteFPR. -class WriteFPROperation : public Operation -{ +class WriteFPROperation : public Operation { public: - WriteFPROperation(lldb::tid_t tid, void *buf, bool &result) - : m_tid(tid), m_buf(buf), m_result(result) - { } + WriteFPROperation(lldb::tid_t tid, void *buf, bool &result) + : m_tid(tid), m_buf(buf), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - void *m_buf; - bool &m_result; + lldb::tid_t m_tid; + void *m_buf; + bool &m_result; }; -void -WriteFPROperation::Execute(ProcessMonitor *monitor) -{ - if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) - m_result = false; - else - m_result = true; +void WriteFPROperation::Execute(ProcessMonitor *monitor) { + if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class ResumeOperation /// @brief Implements ProcessMonitor::Resume. -class ResumeOperation : public Operation -{ +class ResumeOperation : public Operation { public: - ResumeOperation(uint32_t signo, bool &result) : - m_signo(signo), m_result(result) { } + ResumeOperation(uint32_t signo, bool &result) + : m_signo(signo), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - uint32_t m_signo; - bool &m_result; + uint32_t m_signo; + bool &m_result; }; -void -ResumeOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); - int data = 0; +void ResumeOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); + int data = 0; - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; + if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) + data = m_signo; - if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) - { - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - if (log) - log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", pid, strerror(errno)); - m_result = false; - } - else - m_result = true; + if (log) + log->Printf("ResumeOperation (%" PRIu64 ") failed: %s", pid, + strerror(errno)); + m_result = false; + } else + m_result = true; } //------------------------------------------------------------------------------ /// @class SingleStepOperation /// @brief Implements ProcessMonitor::SingleStep. -class SingleStepOperation : public Operation -{ +class SingleStepOperation : public Operation { public: - SingleStepOperation(uint32_t signo, bool &result) - : m_signo(signo), m_result(result) { } + SingleStepOperation(uint32_t signo, bool &result) + : m_signo(signo), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - uint32_t m_signo; - bool &m_result; + uint32_t m_signo; + bool &m_result; }; -void -SingleStepOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); - int data = 0; +void SingleStepOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); + int data = 0; - if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) - data = m_signo; + if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) + data = m_signo; - if (PTRACE(PT_STEP, pid, NULL, data)) - m_result = false; - else - m_result = true; + if (PTRACE(PT_STEP, pid, NULL, data)) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class LwpInfoOperation /// @brief Implements ProcessMonitor::GetLwpInfo. -class LwpInfoOperation : public Operation -{ +class LwpInfoOperation : public Operation { public: - LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err) - : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { } + LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err) + : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - void *m_info; - bool &m_result; - int &m_err; + lldb::tid_t m_tid; + void *m_info; + bool &m_result; + int &m_err; }; -void -LwpInfoOperation::Execute(ProcessMonitor *monitor) -{ - struct ptrace_lwpinfo plwp; - - if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) { - m_result = false; - m_err = errno; - } else { - memcpy(m_info, &plwp, sizeof(plwp)); - m_result = true; - } +void LwpInfoOperation::Execute(ProcessMonitor *monitor) { + struct ptrace_lwpinfo plwp; + + if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) { + m_result = false; + m_err = errno; + } else { + memcpy(m_info, &plwp, sizeof(plwp)); + m_result = true; + } } //------------------------------------------------------------------------------ /// @class ThreadSuspendOperation /// @brief Implements ProcessMonitor::ThreadSuspend. -class ThreadSuspendOperation : public Operation -{ +class ThreadSuspendOperation : public Operation { public: - ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) - : m_tid(tid), m_suspend(suspend), m_result(result) { } + ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result) + : m_tid(tid), m_suspend(suspend), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - bool m_suspend; - bool &m_result; -} ; - -void -ThreadSuspendOperation::Execute(ProcessMonitor *monitor) -{ - m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0); -} - + lldb::tid_t m_tid; + bool m_suspend; + bool &m_result; +}; +void ThreadSuspendOperation::Execute(ProcessMonitor *monitor) { + m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0); +} //------------------------------------------------------------------------------ /// @class EventMessageOperation /// @brief Implements ProcessMonitor::GetEventMessage. -class EventMessageOperation : public Operation -{ +class EventMessageOperation : public Operation { public: - EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result) - : m_tid(tid), m_message(message), m_result(result) { } + EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result) + : m_tid(tid), m_message(message), m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; - unsigned long *m_message; - bool &m_result; + lldb::tid_t m_tid; + unsigned long *m_message; + bool &m_result; }; -void -EventMessageOperation::Execute(ProcessMonitor *monitor) -{ - struct ptrace_lwpinfo plwp; +void EventMessageOperation::Execute(ProcessMonitor *monitor) { + struct ptrace_lwpinfo plwp; - if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) - m_result = false; - else { - if (plwp.pl_flags & PL_FLAG_FORKED) { - *m_message = plwp.pl_child_pid; - m_result = true; - } else - m_result = false; - } + if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) + m_result = false; + else { + if (plwp.pl_flags & PL_FLAG_FORKED) { + *m_message = plwp.pl_child_pid; + m_result = true; + } else + m_result = false; + } } //------------------------------------------------------------------------------ /// @class KillOperation /// @brief Implements ProcessMonitor::Kill. -class KillOperation : public Operation -{ +class KillOperation : public Operation { public: - KillOperation(bool &result) : m_result(result) { } + KillOperation(bool &result) : m_result(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - bool &m_result; + bool &m_result; }; -void -KillOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); +void KillOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); - if (PTRACE(PT_KILL, pid, NULL, 0)) - m_result = false; - else - m_result = true; + if (PTRACE(PT_KILL, pid, NULL, 0)) + m_result = false; + else + m_result = true; } //------------------------------------------------------------------------------ /// @class DetachOperation /// @brief Implements ProcessMonitor::Detach. -class DetachOperation : public Operation -{ +class DetachOperation : public Operation { public: - DetachOperation(Error &result) : m_error(result) { } + DetachOperation(Error &result) : m_error(result) {} - void Execute(ProcessMonitor *monitor); + void Execute(ProcessMonitor *monitor); private: - Error &m_error; + Error &m_error; }; -void -DetachOperation::Execute(ProcessMonitor *monitor) -{ - lldb::pid_t pid = monitor->GetPID(); +void DetachOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); - if (PTRACE(PT_DETACH, pid, NULL, 0) < 0) - m_error.SetErrorToErrno(); - + if (PTRACE(PT_DETACH, pid, NULL, 0) < 0) + m_error.SetErrorToErrno(); } ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor) - : m_monitor(monitor) -{ - sem_init(&m_semaphore, 0, 0); + : m_monitor(monitor) { + sem_init(&m_semaphore, 0, 0); } -ProcessMonitor::OperationArgs::~OperationArgs() -{ - sem_destroy(&m_semaphore); -} +ProcessMonitor::OperationArgs::~OperationArgs() { sem_destroy(&m_semaphore); } ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, - char const **argv, - char const **envp, + char const **argv, char const **envp, const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, const FileSpec &working_dir) - : OperationArgs(monitor), - m_module(module), - m_argv(argv), - m_envp(envp), - m_stdin_file_spec(stdin_file_spec), - m_stdout_file_spec(stdout_file_spec), - m_stderr_file_spec(stderr_file_spec), - m_working_dir(working_dir) { } + : OperationArgs(monitor), m_module(module), m_argv(argv), m_envp(envp), + m_stdin_file_spec(stdin_file_spec), m_stdout_file_spec(stdout_file_spec), + m_stderr_file_spec(stderr_file_spec), m_working_dir(working_dir) {} -ProcessMonitor::LaunchArgs::~LaunchArgs() -{ } +ProcessMonitor::LaunchArgs::~LaunchArgs() {} -ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor, - lldb::pid_t pid) - : OperationArgs(monitor), m_pid(pid) { } +ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor, lldb::pid_t pid) + : OperationArgs(monitor), m_pid(pid) {} -ProcessMonitor::AttachArgs::~AttachArgs() -{ } +ProcessMonitor::AttachArgs::~AttachArgs() {} //------------------------------------------------------------------------------ /// The basic design of the ProcessMonitor is built around two threads. /// /// One thread (@see SignalThread) simply blocks on a call to waitpid() looking /// for changes in the debugee state. When a change is detected a -/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This thread +/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This +/// thread /// "drives" state changes in the debugger. /// /// The second thread (@see OperationThread) is responsible for two things 1) /// launching or attaching to the inferior process, and then 2) servicing /// operations such as register reads/writes, stepping, etc. See the comments /// on the Operation class for more info as to why this is needed. -ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, - Module *module, - const char *argv[], - const char *envp[], - const FileSpec &stdin_file_spec, - const FileSpec &stdout_file_spec, - const FileSpec &stderr_file_spec, - const FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo & /* launch_info */, - lldb_private::Error &error) +ProcessMonitor::ProcessMonitor( + ProcessFreeBSD *process, Module *module, const char *argv[], + const char *envp[], const FileSpec &stdin_file_spec, + const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, + const FileSpec &working_dir, + const lldb_private::ProcessLaunchInfo & /* launch_info */, + lldb_private::Error &error) : m_process(static_cast<ProcessFreeBSD *>(process)), - m_pid(LLDB_INVALID_PROCESS_ID), - m_terminal_fd(-1), - m_operation(0) -{ - using namespace std::placeholders; - - std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp, - stdin_file_spec, - stdout_file_spec, - stderr_file_spec, - working_dir)); - - - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); - - StartLaunchOpThread(args.get(), error); - if (!error.Success()) - return; + m_pid(LLDB_INVALID_PROCESS_ID), m_terminal_fd(-1), m_operation(0) { + using namespace std::placeholders; -WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) - { - if (errno == EINTR) - goto WAIT_AGAIN; - else - { - error.SetErrorToErrno(); - return; - } - } + std::unique_ptr<LaunchArgs> args( + new LaunchArgs(this, module, argv, envp, stdin_file_spec, + stdout_file_spec, stderr_file_spec, working_dir)); - // Check that the launch was a success. - if (!args->m_error.Success()) - { - StopOpThread(); - error = args->m_error; - return; - } + sem_init(&m_operation_pending, 0, 0); + sem_init(&m_operation_done, 0, 0); + + StartLaunchOpThread(args.get(), error); + if (!error.Success()) + return; - // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess( - std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), GetPID(), true); - if (!m_monitor_thread.IsJoinable()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Process launch failed."); - return; +WAIT_AGAIN: + // Wait for the operation thread to initialize. + if (sem_wait(&args->m_semaphore)) { + if (errno == EINTR) + goto WAIT_AGAIN; + else { + error.SetErrorToErrno(); + return; } -} + } -ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, - lldb::pid_t pid, + // Check that the launch was a success. + if (!args->m_error.Success()) { + StopOpThread(); + error = args->m_error; + return; + } + + // Finally, start monitoring the child process for change in state. + m_monitor_thread = Host::StartMonitoringChildProcess( + std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), + GetPID(), true); + if (!m_monitor_thread.IsJoinable()) { + error.SetErrorToGenericError(); + error.SetErrorString("Process launch failed."); + return; + } +} + +ProcessMonitor::ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid, lldb_private::Error &error) - : m_process(static_cast<ProcessFreeBSD *>(process)), - m_pid(pid), - m_terminal_fd(-1), - m_operation(0) -{ - using namespace std::placeholders; - - sem_init(&m_operation_pending, 0, 0); - sem_init(&m_operation_done, 0, 0); + : m_process(static_cast<ProcessFreeBSD *>(process)), m_pid(pid), + m_terminal_fd(-1), m_operation(0) { + using namespace std::placeholders; + sem_init(&m_operation_pending, 0, 0); + sem_init(&m_operation_done, 0, 0); - std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid)); + std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid)); - StartAttachOpThread(args.get(), error); - if (!error.Success()) - return; + StartAttachOpThread(args.get(), error); + if (!error.Success()) + return; WAIT_AGAIN: - // Wait for the operation thread to initialize. - if (sem_wait(&args->m_semaphore)) - { - if (errno == EINTR) - goto WAIT_AGAIN; - else - { - error.SetErrorToErrno(); - return; - } + // Wait for the operation thread to initialize. + if (sem_wait(&args->m_semaphore)) { + if (errno == EINTR) + goto WAIT_AGAIN; + else { + error.SetErrorToErrno(); + return; } + } - // Check that the attach was a success. - if (!args->m_error.Success()) - { - StopOpThread(); - error = args->m_error; - return; - } + // Check that the attach was a success. + if (!args->m_error.Success()) { + StopOpThread(); + error = args->m_error; + return; + } - // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess( - std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), GetPID(), true); - if (!m_monitor_thread.IsJoinable()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Process attach failed."); - return; - } + // Finally, start monitoring the child process for change in state. + m_monitor_thread = Host::StartMonitoringChildProcess( + std::bind(&ProcessMonitor::MonitorCallback, this, _1, _2, _3, _4), + GetPID(), true); + if (!m_monitor_thread.IsJoinable()) { + error.SetErrorToGenericError(); + error.SetErrorString("Process attach failed."); + return; + } } -ProcessMonitor::~ProcessMonitor() -{ - StopMonitor(); -} +ProcessMonitor::~ProcessMonitor() { StopMonitor(); } //------------------------------------------------------------------------------ // Thread setup and tear down. -void -ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error) -{ - static const char *g_thread_name = "lldb.process.freebsd.operation"; +void ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error) { + static const char *g_thread_name = "lldb.process.freebsd.operation"; - if (m_operation_thread.IsJoinable()) - return; + if (m_operation_thread.IsJoinable()) + return; - m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error); + m_operation_thread = + ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error); } -void * -ProcessMonitor::LaunchOpThread(void *arg) -{ - LaunchArgs *args = static_cast<LaunchArgs*>(arg); +void *ProcessMonitor::LaunchOpThread(void *arg) { + LaunchArgs *args = static_cast<LaunchArgs *>(arg); - if (!Launch(args)) { - sem_post(&args->m_semaphore); - return NULL; - } - - ServeOperation(args); + if (!Launch(args)) { + sem_post(&args->m_semaphore); return NULL; -} - -bool -ProcessMonitor::Launch(LaunchArgs *args) -{ - ProcessMonitor *monitor = args->m_monitor; - ProcessFreeBSD &process = monitor->GetProcess(); - const char **argv = args->m_argv; - const char **envp = args->m_envp; - const FileSpec &stdin_file_spec = args->m_stdin_file_spec; - const FileSpec &stdout_file_spec = args->m_stdout_file_spec; - const FileSpec &stderr_file_spec = args->m_stderr_file_spec; - const FileSpec &working_dir = args->m_working_dir; - - lldb_utility::PseudoTerminal terminal; - const size_t err_len = 1024; - char err_str[err_len]; - ::pid_t pid; - - // Propagate the environment if one is not supplied. - if (envp == NULL || envp[0] == NULL) - envp = const_cast<const char **>(environ); - - if ((pid = terminal.Fork(err_str, err_len)) == -1) - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Process fork failed."); - goto FINISH; - } - - // Recognized child exit status codes. - enum { - ePtraceFailed = 1, - eDupStdinFailed, - eDupStdoutFailed, - eDupStderrFailed, - eChdirFailed, - eExecFailed, - eSetGidFailed - }; - - // Child process. - if (pid == 0) - { - // Trace this process. - if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0) - exit(ePtraceFailed); - - // terminal has already dupped the tty descriptors to stdin/out/err. - // This closes original fd from which they were copied (and avoids - // leaking descriptors to the debugged process. - terminal.CloseSlaveFileDescriptor(); - - // Do not inherit setgid powers. - if (setgid(getgid()) != 0) - exit(eSetGidFailed); - - // Let us have our own process group. - setpgid(0, 0); - - // Dup file descriptors if needed. - // - // FIXME: If two or more of the paths are the same we needlessly open - // the same file multiple times. - if (stdin_file_spec) - if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY)) - exit(eDupStdinFailed); - - if (stdout_file_spec) - if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStdoutFailed); - - if (stderr_file_spec) - if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT)) - exit(eDupStderrFailed); - - // Change working directory - if (working_dir && 0 != ::chdir(working_dir.GetCString())) - exit(eChdirFailed); - - // Execute. We should never return. - execve(argv[0], - const_cast<char *const *>(argv), - const_cast<char *const *>(envp)); - exit(eExecFailed); - } - - // Wait for the child process to to trap on its call to execve. - ::pid_t wpid; - int status; - if ((wpid = waitpid(pid, &status, 0)) < 0) - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } - else if (WIFEXITED(status)) - { - // open, dup or execve likely failed for some reason. - args->m_error.SetErrorToGenericError(); - switch (WEXITSTATUS(status)) - { - case ePtraceFailed: - args->m_error.SetErrorString("Child ptrace failed."); - break; - case eDupStdinFailed: - args->m_error.SetErrorString("Child open stdin failed."); - break; - case eDupStdoutFailed: - args->m_error.SetErrorString("Child open stdout failed."); - break; - case eDupStderrFailed: - args->m_error.SetErrorString("Child open stderr failed."); - break; - case eChdirFailed: - args->m_error.SetErrorString("Child failed to set working directory."); - break; - case eExecFailed: - args->m_error.SetErrorString("Child exec failed."); - break; - case eSetGidFailed: - args->m_error.SetErrorString("Child setgid failed."); - break; - default: - args->m_error.SetErrorString("Child returned unknown exit status."); - break; - } - goto FINISH; + } + + ServeOperation(args); + return NULL; +} + +bool ProcessMonitor::Launch(LaunchArgs *args) { + ProcessMonitor *monitor = args->m_monitor; + ProcessFreeBSD &process = monitor->GetProcess(); + const char **argv = args->m_argv; + const char **envp = args->m_envp; + const FileSpec &stdin_file_spec = args->m_stdin_file_spec; + const FileSpec &stdout_file_spec = args->m_stdout_file_spec; + const FileSpec &stderr_file_spec = args->m_stderr_file_spec; + const FileSpec &working_dir = args->m_working_dir; + + lldb_utility::PseudoTerminal terminal; + const size_t err_len = 1024; + char err_str[err_len]; + ::pid_t pid; + + // Propagate the environment if one is not supplied. + if (envp == NULL || envp[0] == NULL) + envp = const_cast<const char **>(environ); + + if ((pid = terminal.Fork(err_str, err_len)) == -1) { + args->m_error.SetErrorToGenericError(); + args->m_error.SetErrorString("Process fork failed."); + goto FINISH; + } + + // Recognized child exit status codes. + enum { + ePtraceFailed = 1, + eDupStdinFailed, + eDupStdoutFailed, + eDupStderrFailed, + eChdirFailed, + eExecFailed, + eSetGidFailed + }; + + // Child process. + if (pid == 0) { + // Trace this process. + if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0) + exit(ePtraceFailed); + + // terminal has already dupped the tty descriptors to stdin/out/err. + // This closes original fd from which they were copied (and avoids + // leaking descriptors to the debugged process. + terminal.CloseSlaveFileDescriptor(); + + // Do not inherit setgid powers. + if (setgid(getgid()) != 0) + exit(eSetGidFailed); + + // Let us have our own process group. + setpgid(0, 0); + + // Dup file descriptors if needed. + // + // FIXME: If two or more of the paths are the same we needlessly open + // the same file multiple times. + if (stdin_file_spec) + if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY)) + exit(eDupStdinFailed); + + if (stdout_file_spec) + if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT)) + exit(eDupStdoutFailed); + + if (stderr_file_spec) + if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT)) + exit(eDupStderrFailed); + + // Change working directory + if (working_dir && 0 != ::chdir(working_dir.GetCString())) + exit(eChdirFailed); + + // Execute. We should never return. + execve(argv[0], const_cast<char *const *>(argv), + const_cast<char *const *>(envp)); + exit(eExecFailed); + } + + // Wait for the child process to to trap on its call to execve. + ::pid_t wpid; + int status; + if ((wpid = waitpid(pid, &status, 0)) < 0) { + args->m_error.SetErrorToErrno(); + goto FINISH; + } else if (WIFEXITED(status)) { + // open, dup or execve likely failed for some reason. + args->m_error.SetErrorToGenericError(); + switch (WEXITSTATUS(status)) { + case ePtraceFailed: + args->m_error.SetErrorString("Child ptrace failed."); + break; + case eDupStdinFailed: + args->m_error.SetErrorString("Child open stdin failed."); + break; + case eDupStdoutFailed: + args->m_error.SetErrorString("Child open stdout failed."); + break; + case eDupStderrFailed: + args->m_error.SetErrorString("Child open stderr failed."); + break; + case eChdirFailed: + args->m_error.SetErrorString("Child failed to set working directory."); + break; + case eExecFailed: + args->m_error.SetErrorString("Child exec failed."); + break; + case eSetGidFailed: + args->m_error.SetErrorString("Child setgid failed."); + break; + default: + args->m_error.SetErrorString("Child returned unknown exit status."); + break; } - assert(WIFSTOPPED(status) && wpid == (::pid_t)pid && - "Could not sync with inferior process."); + goto FINISH; + } + assert(WIFSTOPPED(status) && wpid == (::pid_t)pid && + "Could not sync with inferior process."); #ifdef notyet - // Have the child raise an event on exit. This is used to keep the child in - // limbo until it is destroyed. - if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0) - { - args->m_error.SetErrorToErrno(); - goto FINISH; - } + // Have the child raise an event on exit. This is used to keep the child in + // limbo until it is destroyed. + if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0) { + args->m_error.SetErrorToErrno(); + goto FINISH; + } #endif - // Release the master terminal descriptor and pass it off to the - // ProcessMonitor instance. Similarly stash the inferior pid. - monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); - monitor->m_pid = pid; + // Release the master terminal descriptor and pass it off to the + // ProcessMonitor instance. Similarly stash the inferior pid. + monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); + monitor->m_pid = pid; - // Set the terminal fd to be in non blocking mode (it simplifies the - // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking - // descriptor to read from). - if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error)) - goto FINISH; + // Set the terminal fd to be in non blocking mode (it simplifies the + // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking + // descriptor to read from). + if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error)) + goto FINISH; - process.SendMessage(ProcessMessage::Attach(pid)); + process.SendMessage(ProcessMessage::Attach(pid)); FINISH: - return args->m_error.Success(); + return args->m_error.Success(); } -void -ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error) -{ - static const char *g_thread_name = "lldb.process.freebsd.operation"; +void ProcessMonitor::StartAttachOpThread(AttachArgs *args, + lldb_private::Error &error) { + static const char *g_thread_name = "lldb.process.freebsd.operation"; - if (m_operation_thread.IsJoinable()) - return; + if (m_operation_thread.IsJoinable()) + return; - m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error); + m_operation_thread = + ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error); } -void * -ProcessMonitor::AttachOpThread(void *arg) -{ - AttachArgs *args = static_cast<AttachArgs*>(arg); +void *ProcessMonitor::AttachOpThread(void *arg) { + AttachArgs *args = static_cast<AttachArgs *>(arg); - Attach(args); + Attach(args); - ServeOperation(args); - return NULL; + ServeOperation(args); + return NULL; } -void -ProcessMonitor::Attach(AttachArgs *args) -{ - lldb::pid_t pid = args->m_pid; +void ProcessMonitor::Attach(AttachArgs *args) { + lldb::pid_t pid = args->m_pid; - ProcessMonitor *monitor = args->m_monitor; - ProcessFreeBSD &process = monitor->GetProcess(); + ProcessMonitor *monitor = args->m_monitor; + ProcessFreeBSD &process = monitor->GetProcess(); - if (pid <= 1) - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Attaching to process 1 is not allowed."); - return; - } + if (pid <= 1) { + args->m_error.SetErrorToGenericError(); + args->m_error.SetErrorString("Attaching to process 1 is not allowed."); + return; + } - // Attach to the requested process. - if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0) - { - args->m_error.SetErrorToErrno(); - return; - } + // Attach to the requested process. + if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0) { + args->m_error.SetErrorToErrno(); + return; + } - int status; - if ((status = waitpid(pid, NULL, 0)) < 0) - { - args->m_error.SetErrorToErrno(); - return; - } + int status; + if ((status = waitpid(pid, NULL, 0)) < 0) { + args->m_error.SetErrorToErrno(); + return; + } - process.SendMessage(ProcessMessage::Attach(pid)); + process.SendMessage(ProcessMessage::Attach(pid)); } size_t -ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t>&thread_ids) -{ - lwpid_t *tids; - int tdcnt; - - thread_ids.clear(); - - tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0); - if (tdcnt <= 0) - return 0; - tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids)); - if (tids == NULL) - return 0; - if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) { - free(tids); - return 0; - } - thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt); +ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids) { + lwpid_t *tids; + int tdcnt; + + thread_ids.clear(); + + tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0); + if (tdcnt <= 0) + return 0; + tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids)); + if (tids == NULL) + return 0; + if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) { free(tids); - return thread_ids.size(); + return 0; + } + thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt); + free(tids); + return thread_ids.size(); } -bool -ProcessMonitor::MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, bool exited, int signal, int status) -{ - ProcessMessage message; - ProcessFreeBSD *process = monitor->m_process; - assert(process); - bool stop_monitoring; - struct ptrace_lwpinfo plwp; - int ptrace_err; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - if (exited) - { - if (log) - log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid); - message = ProcessMessage::Exit(pid, status); - process->SendMessage(message); - return pid == process->GetID(); - } +bool ProcessMonitor::MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, + bool exited, int signal, int status) { + ProcessMessage message; + ProcessFreeBSD *process = monitor->m_process; + assert(process); + bool stop_monitoring; + struct ptrace_lwpinfo plwp; + int ptrace_err; - if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err)) - stop_monitoring = true; // pid is gone. Bail. - else { - switch (plwp.pl_siginfo.si_signo) - { - case SIGTRAP: - message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); - break; - - default: - message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); - break; - } - - process->SendMessage(message); - stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage; - } - - return stop_monitoring; -} + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); -ProcessMessage -ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::tid_t tid) -{ - ProcessMessage message; - - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - assert(monitor); - assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!"); + if (exited) { + if (log) + log->Printf("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, + __FUNCTION__, pid); + message = ProcessMessage::Exit(pid, status); + process->SendMessage(message); + return pid == process->GetID(); + } + + if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err)) + stop_monitoring = true; // pid is gone. Bail. + else { + switch (plwp.pl_siginfo.si_signo) { + case SIGTRAP: + message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); + break; - switch (info->si_code) - { default: - assert(false && "Unexpected SIGTRAP code!"); - break; - - case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */): - { - // The inferior process is about to exit. Maintain the process in a - // state of "limbo" until we are explicitly commanded to detach, - // destroy, resume, etc. - unsigned long data = 0; - if (!monitor->GetEventMessage(tid, &data)) - data = -1; - if (log) - log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, tid = %" PRIu64, __FUNCTION__, data, tid); - message = ProcessMessage::Limbo(tid, (data >> 8)); - break; + message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid); + break; } - case 0: - case TRAP_TRACE: - if (log) - log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64 " : si_code = %d", __FUNCTION__, tid, info->si_code); - message = ProcessMessage::Trace(tid); - break; - - case SI_KERNEL: - case TRAP_BRKPT: - if (log) - log->Printf ("ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, __FUNCTION__, tid); - message = ProcessMessage::Break(tid); - break; - } + process->SendMessage(message); + stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage; + } - return message; + return stop_monitoring; } -ProcessMessage -ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::tid_t tid) -{ - ProcessMessage message; - int signo = info->si_signo; +ProcessMessage ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, + const siginfo_t *info, + lldb::tid_t tid) { + ProcessMessage message; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - // POSIX says that process behaviour is undefined after it ignores a SIGFPE, - // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a - // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD. - // - // IOW, user generated signals never generate what we consider to be a - // "crash". - // - // Similarly, ACK signals generated by this monitor. - if (info->si_code == SI_USER) - { - if (log) - log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d", - __FUNCTION__, - monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo), - "SI_USER", - info->si_pid); - if (info->si_pid == getpid()) - return ProcessMessage::SignalDelivered(tid, signo); - else - return ProcessMessage::Signal(tid, signo); - } + assert(monitor); + assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!"); + switch (info->si_code) { + default: + assert(false && "Unexpected SIGTRAP code!"); + break; + + case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */): { + // The inferior process is about to exit. Maintain the process in a + // state of "limbo" until we are explicitly commanded to detach, + // destroy, resume, etc. + unsigned long data = 0; + if (!monitor->GetEventMessage(tid, &data)) + data = -1; if (log) - log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo)); - - switch (signo) - { - case SIGSEGV: - case SIGILL: - case SIGFPE: - case SIGBUS: - lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); - const auto reason = GetCrashReason(*info); - return ProcessMessage::Crash(tid, reason, signo, fault_addr); - } + log->Printf("ProcessMonitor::%s() received exit? event, data = %lx, tid " + "= %" PRIu64, + __FUNCTION__, data, tid); + message = ProcessMessage::Limbo(tid, (data >> 8)); + break; + } + + case 0: + case TRAP_TRACE: + if (log) + log->Printf("ProcessMonitor::%s() received trace event, tid = %" PRIu64 + " : si_code = %d", + __FUNCTION__, tid, info->si_code); + message = ProcessMessage::Trace(tid); + break; + + case SI_KERNEL: + case TRAP_BRKPT: + if (log) + log->Printf( + "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, + __FUNCTION__, tid); + message = ProcessMessage::Break(tid); + break; + } + + return message; +} + +ProcessMessage ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, + const siginfo_t *info, + lldb::tid_t tid) { + ProcessMessage message; + int signo = info->si_signo; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + // POSIX says that process behaviour is undefined after it ignores a SIGFPE, + // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a + // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD. + // + // IOW, user generated signals never generate what we consider to be a + // "crash". + // + // Similarly, ACK signals generated by this monitor. + if (info->si_code == SI_USER) { + if (log) + log->Printf( + "ProcessMonitor::%s() received signal %s with code %s, pid = %d", + __FUNCTION__, + monitor->m_process->GetUnixSignals()->GetSignalAsCString(signo), + "SI_USER", info->si_pid); + if (info->si_pid == getpid()) + return ProcessMessage::SignalDelivered(tid, signo); + else + return ProcessMessage::Signal(tid, signo); + } + + if (log) + log->Printf( + "ProcessMonitor::%s() received signal %s", __FUNCTION__, + monitor->m_process->GetUnixSignals()->GetSignalAsCString(signo)); - // Everything else is "normal" and does not require any special action on - // our part. - return ProcessMessage::Signal(tid, signo); + switch (signo) { + case SIGSEGV: + case SIGILL: + case SIGFPE: + case SIGBUS: + lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr); + const auto reason = GetCrashReason(*info); + return ProcessMessage::Crash(tid, reason, signo, fault_addr); + } + + // Everything else is "normal" and does not require any special action on + // our part. + return ProcessMessage::Signal(tid, signo); } -void -ProcessMonitor::ServeOperation(OperationArgs *args) -{ - ProcessMonitor *monitor = args->m_monitor; +void ProcessMonitor::ServeOperation(OperationArgs *args) { + ProcessMonitor *monitor = args->m_monitor; - // We are finised with the arguments and are ready to go. Sync with the - // parent thread and start serving operations on the inferior. - sem_post(&args->m_semaphore); + // We are finised with the arguments and are ready to go. Sync with the + // parent thread and start serving operations on the inferior. + sem_post(&args->m_semaphore); - for (;;) - { - // wait for next pending operation - sem_wait(&monitor->m_operation_pending); + for (;;) { + // wait for next pending operation + sem_wait(&monitor->m_operation_pending); - monitor->m_operation->Execute(monitor); + monitor->m_operation->Execute(monitor); - // notify calling thread that operation is complete - sem_post(&monitor->m_operation_done); - } + // notify calling thread that operation is complete + sem_post(&monitor->m_operation_done); + } } -void -ProcessMonitor::DoOperation(Operation *op) -{ - std::lock_guard<std::mutex> guard(m_operation_mutex); +void ProcessMonitor::DoOperation(Operation *op) { + std::lock_guard<std::mutex> guard(m_operation_mutex); - m_operation = op; + m_operation = op; - // notify operation thread that an operation is ready to be processed - sem_post(&m_operation_pending); + // notify operation thread that an operation is ready to be processed + sem_post(&m_operation_pending); - // wait for operation to complete - sem_wait(&m_operation_done); + // wait for operation to complete + sem_wait(&m_operation_done); } -size_t -ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Error &error) -{ - size_t result; - ReadOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; +size_t ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Error &error) { + size_t result; + ReadOperation op(vm_addr, buf, size, error, result); + DoOperation(&op); + return result; } -size_t -ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error) -{ - size_t result; - WriteOperation op(vm_addr, buf, size, error, result); - DoOperation(&op); - return result; +size_t ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, + size_t size, lldb_private::Error &error) { + size_t result; + WriteOperation op(vm_addr, buf, size, error, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name, - unsigned size, RegisterValue &value) -{ - bool result; - ReadRegOperation op(tid, offset, size, value, result); - DoOperation(&op); - return result; +bool ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, unsigned size, + RegisterValue &value) { + bool result; + ReadRegOperation op(tid, offset, size, value, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, - const char* reg_name, const RegisterValue &value) -{ - bool result; - WriteRegOperation op(tid, offset, value, result); - DoOperation(&op); - return result; +bool ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, + const RegisterValue &value) { + bool result; + WriteRegOperation op(tid, offset, value, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, unsigned size, - lldb_private::RegisterValue &value) -{ - bool result; - ReadDebugRegOperation op(tid, offset, size, value, result); - DoOperation(&op); - return result; +bool ProcessMonitor::ReadDebugRegisterValue( + lldb::tid_t tid, unsigned offset, const char *reg_name, unsigned size, + lldb_private::RegisterValue &value) { + bool result; + ReadDebugRegOperation op(tid, offset, size, value, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, - const lldb_private::RegisterValue &value) -{ - bool result; - WriteDebugRegOperation op(tid, offset, value, result); - DoOperation(&op); - return result; +bool ProcessMonitor::WriteDebugRegisterValue( + lldb::tid_t tid, unsigned offset, const char *reg_name, + const lldb_private::RegisterValue &value) { + bool result; + WriteDebugRegOperation op(tid, offset, value, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - ReadGPROperation op(tid, buf, result); - DoOperation(&op); - return result; +bool ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size) { + bool result; + ReadGPROperation op(tid, buf, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - ReadFPROperation op(tid, buf, result); - DoOperation(&op); - return result; +bool ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size) { + bool result; + ReadFPROperation op(tid, buf, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) -{ - return false; +bool ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, + size_t buf_size, unsigned int regset) { + return false; } -bool -ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - WriteGPROperation op(tid, buf, result); - DoOperation(&op); - return result; +bool ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size) { + bool result; + WriteGPROperation op(tid, buf, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size) -{ - bool result; - WriteFPROperation op(tid, buf, result); - DoOperation(&op); - return result; +bool ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size) { + bool result; + WriteFPROperation op(tid, buf, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset) -{ - return false; +bool ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, + size_t buf_size, unsigned int regset) { + return false; } -bool -ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) -{ - return false; +bool ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) { + return false; } -bool -ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) -{ - bool result; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - - if (log) { - const char *signame = m_process->GetUnixSignals()->GetSignalAsCString (signo); - if (signame == nullptr) - signame = "<none>"; - log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", - __FUNCTION__, GetPID(), signame); - } - ResumeOperation op(signo, result); - DoOperation(&op); - if (log) - log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false"); - return result; +bool ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) { + bool result; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + if (log) { + const char *signame = + m_process->GetUnixSignals()->GetSignalAsCString(signo); + if (signame == nullptr) + signame = "<none>"; + log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", + __FUNCTION__, GetPID(), signame); + } + ResumeOperation op(signo, result); + DoOperation(&op); + if (log) + log->Printf("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, + result ? "true" : "false"); + return result; } -bool -ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) -{ - bool result; - SingleStepOperation op(signo, result); - DoOperation(&op); - return result; +bool ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) { + bool result; + SingleStepOperation op(signo, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::Kill() -{ - bool result; - KillOperation op(result); - DoOperation(&op); - return result; +bool ProcessMonitor::Kill() { + bool result; + KillOperation op(result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err) -{ - bool result; - LwpInfoOperation op(tid, lwpinfo, result, ptrace_err); - DoOperation(&op); - return result; +bool ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, + int &ptrace_err) { + bool result; + LwpInfoOperation op(tid, lwpinfo, result, ptrace_err); + DoOperation(&op); + return result; } -bool -ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend) -{ - bool result; - ThreadSuspendOperation op(tid, suspend, result); - DoOperation(&op); - return result; +bool ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend) { + bool result; + ThreadSuspendOperation op(tid, suspend, result); + DoOperation(&op); + return result; } -bool -ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) -{ - bool result; - EventMessageOperation op(tid, message, result); - DoOperation(&op); - return result; +bool ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message) { + bool result; + EventMessageOperation op(tid, message, result); + DoOperation(&op); + return result; } -lldb_private::Error -ProcessMonitor::Detach(lldb::tid_t tid) -{ - lldb_private::Error error; - if (tid != LLDB_INVALID_THREAD_ID) - { - DetachOperation op(error); - DoOperation(&op); - } - return error; -} +lldb_private::Error ProcessMonitor::Detach(lldb::tid_t tid) { + lldb_private::Error error; + if (tid != LLDB_INVALID_THREAD_ID) { + DetachOperation op(error); + DoOperation(&op); + } + return error; +} -bool -ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, int flags) -{ - int target_fd = open(file_spec.GetCString(), flags, 0666); +bool ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, + int flags) { + int target_fd = open(file_spec.GetCString(), flags, 0666); - if (target_fd == -1) - return false; + if (target_fd == -1) + return false; - if (dup2(target_fd, fd) == -1) - return false; + if (dup2(target_fd, fd) == -1) + return false; - return (close(target_fd) == -1) ? false : true; + return (close(target_fd) == -1) ? false : true; } -void -ProcessMonitor::StopMonitoringChildProcess() -{ - if (m_monitor_thread.IsJoinable()) - { - m_monitor_thread.Cancel(); - m_monitor_thread.Join(nullptr); - m_monitor_thread.Reset(); - } +void ProcessMonitor::StopMonitoringChildProcess() { + if (m_monitor_thread.IsJoinable()) { + m_monitor_thread.Cancel(); + m_monitor_thread.Join(nullptr); + m_monitor_thread.Reset(); + } } -void -ProcessMonitor::StopMonitor() -{ - StopMonitoringChildProcess(); - StopOpThread(); - sem_destroy(&m_operation_pending); - sem_destroy(&m_operation_done); - if (m_terminal_fd >= 0) { - close(m_terminal_fd); - m_terminal_fd = -1; - } +void ProcessMonitor::StopMonitor() { + StopMonitoringChildProcess(); + StopOpThread(); + sem_destroy(&m_operation_pending); + sem_destroy(&m_operation_done); + if (m_terminal_fd >= 0) { + close(m_terminal_fd); + m_terminal_fd = -1; + } } // FIXME: On Linux, when a new thread is created, we receive to notifications, @@ -1607,19 +1439,13 @@ ProcessMonitor::StopMonitor() // We really should figure out what actually happens on FreeBSD and move the // Linux-specific logic out of ProcessPOSIX as needed. -bool -ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) -{ - return true; -} +bool ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) { return true; } -void -ProcessMonitor::StopOpThread() -{ - if (!m_operation_thread.IsJoinable()) - return; +void ProcessMonitor::StopOpThread() { + if (!m_operation_thread.IsJoinable()) + return; - m_operation_thread.Cancel(); - m_operation_thread.Join(nullptr); - m_operation_thread.Reset(); + m_operation_thread.Cancel(); + m_operation_thread.Join(nullptr); + m_operation_thread.Reset(); } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 93f6be111361..4c2594e9da6a 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -18,12 +18,11 @@ #include <mutex> // Other libraries and framework includes -#include "lldb/lldb-types.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostThread.h" +#include "lldb/lldb-types.h" -namespace lldb_private -{ +namespace lldb_private { class Error; class Module; class Scalar; @@ -44,285 +43,242 @@ class Operation; /// /// A purposely minimal set of operations are provided to interrogate and change /// the inferior process state. -class ProcessMonitor -{ +class ProcessMonitor { public: - - /// Launches an inferior process ready for debugging. Forms the - /// implementation of Process::DoLaunch. - ProcessMonitor(ProcessFreeBSD *process, - lldb_private::Module *module, - char const *argv[], - char const *envp[], - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir, - const lldb_private::ProcessLaunchInfo &launch_info, - lldb_private::Error &error); - - ProcessMonitor(ProcessFreeBSD *process, - lldb::pid_t pid, - lldb_private::Error &error); - - ~ProcessMonitor(); - - /// Provides the process number of debugee. - lldb::pid_t - GetPID() const { return m_pid; } - - /// Returns the process associated with this ProcessMonitor. - ProcessFreeBSD & - GetProcess() { return *m_process; } - - /// Returns a file descriptor to the controlling terminal of the inferior - /// process. - /// - /// Reads from this file descriptor yield both the standard output and - /// standard error of this debugee. Even if stderr and stdout were - /// redirected on launch it may still happen that data is available on this - /// descriptor (if the inferior process opens /dev/tty, for example). This descriptor is - /// closed after a call to StopMonitor(). - /// - /// If this monitor was attached to an existing process this method returns - /// -1. - int - GetTerminalFD() const { return m_terminal_fd; } - - /// Reads @p size bytes from address @vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoReadMemory. - size_t - ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - lldb_private::Error &error); - - /// Writes @p size bytes from address @p vm_adder in the inferior process - /// address space. - /// - /// This method is provided to implement Process::DoWriteMemory. - size_t - WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - lldb_private::Error &error); - - /// Reads the contents from the register identified by the given (architecture - /// dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, - unsigned size, lldb_private::RegisterValue &value); - - /// Writes the given value to the register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, - const lldb_private::RegisterValue &value); - - /// Reads the contents from the debug register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, unsigned size, - lldb_private::RegisterValue &value); - - /// Writes the given value to the debug register identified by the given - /// (architecture dependent) offset. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, - const char *reg_name, - const lldb_private::RegisterValue &value); - /// Reads all general purpose registers into the specified buffer. - bool - ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Reads all floating point registers into the specified buffer. - bool - ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Reads the specified register set into the specified buffer. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); - - /// Writes all general purpose registers into the specified buffer. - bool - WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes all floating point registers into the specified buffer. - bool - WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); - - /// Writes the specified register set into the specified buffer. - /// - /// This method is provided for use by RegisterContextFreeBSD derivatives. - bool - WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); - - /// Reads the value of the thread-specific pointer for a given thread ID. - bool - ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); - - /// Returns current thread IDs in process - size_t - GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids); - - /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID - /// to the memory region pointed to by @p lwpinfo. - bool - GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no); - - /// Suspends or unsuspends a thread prior to process resume or step. - bool - ThreadSuspend(lldb::tid_t tid, bool suspend); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread IDto the memory pointed to by @p - /// message. - bool - GetEventMessage(lldb::tid_t tid, unsigned long *message); - - /// Resumes the process. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. - bool - Resume(lldb::tid_t unused, uint32_t signo); - - /// Single steps the process. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. - bool - SingleStep(lldb::tid_t unused, uint32_t signo); - - /// Terminate the traced process. - bool - Kill(); - - lldb_private::Error - Detach(lldb::tid_t tid); - - void - StopMonitor(); - - // Waits for the initial stop message from a new thread. - bool - WaitForInitialTIDStop(lldb::tid_t tid); + /// Launches an inferior process ready for debugging. Forms the + /// implementation of Process::DoLaunch. + ProcessMonitor(ProcessFreeBSD *process, lldb_private::Module *module, + char const *argv[], char const *envp[], + const lldb_private::FileSpec &stdin_file_spec, + const lldb_private::FileSpec &stdout_file_spec, + const lldb_private::FileSpec &stderr_file_spec, + const lldb_private::FileSpec &working_dir, + const lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Error &error); + + ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid, + lldb_private::Error &error); + + ~ProcessMonitor(); + + /// Provides the process number of debugee. + lldb::pid_t GetPID() const { return m_pid; } + + /// Returns the process associated with this ProcessMonitor. + ProcessFreeBSD &GetProcess() { return *m_process; } + + /// Returns a file descriptor to the controlling terminal of the inferior + /// process. + /// + /// Reads from this file descriptor yield both the standard output and + /// standard error of this debugee. Even if stderr and stdout were + /// redirected on launch it may still happen that data is available on this + /// descriptor (if the inferior process opens /dev/tty, for example). This + /// descriptor is + /// closed after a call to StopMonitor(). + /// + /// If this monitor was attached to an existing process this method returns + /// -1. + int GetTerminalFD() const { return m_terminal_fd; } + + /// Reads @p size bytes from address @vm_adder in the inferior process + /// address space. + /// + /// This method is provided to implement Process::DoReadMemory. + size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + lldb_private::Error &error); + + /// Writes @p size bytes from address @p vm_adder in the inferior process + /// address space. + /// + /// This method is provided to implement Process::DoWriteMemory. + size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, + lldb_private::Error &error); + + /// Reads the contents from the register identified by the given (architecture + /// dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, + unsigned size, lldb_private::RegisterValue &value); + + /// Writes the given value to the register identified by the given + /// (architecture dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool WriteRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, + const lldb_private::RegisterValue &value); + + /// Reads the contents from the debug register identified by the given + /// (architecture dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, unsigned size, + lldb_private::RegisterValue &value); + + /// Writes the given value to the debug register identified by the given + /// (architecture dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, + const lldb_private::RegisterValue &value); + /// Reads all general purpose registers into the specified buffer. + bool ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); + + /// Reads all floating point registers into the specified buffer. + bool ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); + + /// Reads the specified register set into the specified buffer. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, + unsigned int regset); + + /// Writes all general purpose registers into the specified buffer. + bool WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); + + /// Writes all floating point registers into the specified buffer. + bool WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); + + /// Writes the specified register set into the specified buffer. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, + unsigned int regset); + + /// Reads the value of the thread-specific pointer for a given thread ID. + bool ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); + + /// Returns current thread IDs in process + size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids); + + /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID + /// to the memory region pointed to by @p lwpinfo. + bool GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no); + + /// Suspends or unsuspends a thread prior to process resume or step. + bool ThreadSuspend(lldb::tid_t tid, bool suspend); + + /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) + /// corresponding to the given thread IDto the memory pointed to by @p + /// message. + bool GetEventMessage(lldb::tid_t tid, unsigned long *message); + + /// Resumes the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. + bool Resume(lldb::tid_t unused, uint32_t signo); + + /// Single steps the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. + bool SingleStep(lldb::tid_t unused, uint32_t signo); + + /// Terminate the traced process. + bool Kill(); + + lldb_private::Error Detach(lldb::tid_t tid); + + void StopMonitor(); + + // Waits for the initial stop message from a new thread. + bool WaitForInitialTIDStop(lldb::tid_t tid); private: - ProcessFreeBSD *m_process; + ProcessFreeBSD *m_process; - lldb_private::HostThread m_operation_thread; - lldb_private::HostThread m_monitor_thread; - lldb::pid_t m_pid; + lldb_private::HostThread m_operation_thread; + lldb_private::HostThread m_monitor_thread; + lldb::pid_t m_pid; - int m_terminal_fd; + int m_terminal_fd; - // current operation which must be executed on the privileged thread - Operation *m_operation; - std::mutex m_operation_mutex; + // current operation which must be executed on the privileged thread + Operation *m_operation; + std::mutex m_operation_mutex; - // semaphores notified when Operation is ready to be processed and when - // the operation is complete. - sem_t m_operation_pending; - sem_t m_operation_done; + // semaphores notified when Operation is ready to be processed and when + // the operation is complete. + sem_t m_operation_pending; + sem_t m_operation_done; - struct OperationArgs - { - OperationArgs(ProcessMonitor *monitor); + struct OperationArgs { + OperationArgs(ProcessMonitor *monitor); - ~OperationArgs(); + ~OperationArgs(); - ProcessMonitor *m_monitor; // The monitor performing the attach. - sem_t m_semaphore; // Posted to once operation complete. - lldb_private::Error m_error; // Set if process operation failed. - }; + ProcessMonitor *m_monitor; // The monitor performing the attach. + sem_t m_semaphore; // Posted to once operation complete. + lldb_private::Error m_error; // Set if process operation failed. + }; - /// @class LauchArgs - /// - /// @brief Simple structure to pass data to the thread responsible for - /// launching a child process. - struct LaunchArgs : OperationArgs - { - LaunchArgs(ProcessMonitor *monitor, - lldb_private::Module *module, - char const **argv, - char const **envp, - const lldb_private::FileSpec &stdin_file_spec, - const lldb_private::FileSpec &stdout_file_spec, - const lldb_private::FileSpec &stderr_file_spec, - const lldb_private::FileSpec &working_dir); + /// @class LauchArgs + /// + /// @brief Simple structure to pass data to the thread responsible for + /// launching a child process. + struct LaunchArgs : OperationArgs { + LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module, + char const **argv, char const **envp, + const lldb_private::FileSpec &stdin_file_spec, + const lldb_private::FileSpec &stdout_file_spec, + const lldb_private::FileSpec &stderr_file_spec, + const lldb_private::FileSpec &working_dir); - ~LaunchArgs(); + ~LaunchArgs(); - lldb_private::Module *m_module; // The executable image to launch. - char const **m_argv; // Process arguments. - char const **m_envp; // Process environment. - const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. - const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty. - const lldb_private::FileSpec m_stderr_file_spec; // Redirect stderr or empty. - const lldb_private::FileSpec m_working_dir; // Working directory or empty. - }; + lldb_private::Module *m_module; // The executable image to launch. + char const **m_argv; // Process arguments. + char const **m_envp; // Process environment. + const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty. + const lldb_private::FileSpec + m_stdout_file_spec; // Redirect stdout or empty. + const lldb_private::FileSpec + m_stderr_file_spec; // Redirect stderr or empty. + const lldb_private::FileSpec m_working_dir; // Working directory or empty. + }; - void - StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error); + void StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error); - static void * - LaunchOpThread(void *arg); + static void *LaunchOpThread(void *arg); - static bool - Launch(LaunchArgs *args); + static bool Launch(LaunchArgs *args); - struct AttachArgs : OperationArgs - { - AttachArgs(ProcessMonitor *monitor, - lldb::pid_t pid); + struct AttachArgs : OperationArgs { + AttachArgs(ProcessMonitor *monitor, lldb::pid_t pid); - ~AttachArgs(); + ~AttachArgs(); - lldb::pid_t m_pid; // pid of the process to be attached. - }; + lldb::pid_t m_pid; // pid of the process to be attached. + }; - void - StartAttachOpThread(AttachArgs *args, lldb_private::Error &error); + void StartAttachOpThread(AttachArgs *args, lldb_private::Error &error); - static void * - AttachOpThread(void *args); + static void *AttachOpThread(void *args); - static void - Attach(AttachArgs *args); + static void Attach(AttachArgs *args); - static void - ServeOperation(OperationArgs *args); + static void ServeOperation(OperationArgs *args); - static bool - DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, int flags); + static bool DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, + int flags); - static bool - MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, bool exited, int signal, int status); + static bool MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid, + bool exited, int signal, int status); - static ProcessMessage - MonitorSIGTRAP(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); + static ProcessMessage MonitorSIGTRAP(ProcessMonitor *monitor, + const siginfo_t *info, lldb::pid_t pid); - static ProcessMessage - MonitorSignal(ProcessMonitor *monitor, - const siginfo_t *info, lldb::pid_t pid); + static ProcessMessage MonitorSignal(ProcessMonitor *monitor, + const siginfo_t *info, lldb::pid_t pid); - void - DoOperation(Operation *op); + void DoOperation(Operation *op); - /// Stops the child monitor thread. - void - StopMonitoringChildProcess(); + /// Stops the child monitor thread. + void StopMonitoringChildProcess(); - /// Stops the operation thread used to attach/launch a process. - void - StopOpThread(); + /// Stops the operation thread used to attach/launch a process. + void StopOpThread(); }; #endif // #ifndef liblldb_ProcessMonitor_H_ diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h index 6ddd9cfe4c21..c0b9b2f4a2d3 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h @@ -13,67 +13,56 @@ // C Includes // C++ Includes // Other libraries and framework includes +#include "RegisterInfoInterface.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Target/RegisterContext.h" -#include "RegisterInfoInterface.h" //------------------------------------------------------------------------------ /// @class POSIXBreakpointProtocol /// /// @brief Extends RegisterClass with a few virtual operations useful on POSIX. -class POSIXBreakpointProtocol -{ +class POSIXBreakpointProtocol { public: - POSIXBreakpointProtocol() - { m_watchpoints_initialized = false; } - virtual ~POSIXBreakpointProtocol() {} + POSIXBreakpointProtocol() { m_watchpoints_initialized = false; } + virtual ~POSIXBreakpointProtocol() {} - /// Updates the register state of the associated thread after hitting a - /// breakpoint (if that make sense for the architecture). Default - /// implementation simply returns true for architectures which do not - /// require any update. - /// - /// @return - /// True if the operation succeeded and false otherwise. - virtual bool UpdateAfterBreakpoint() = 0; + /// Updates the register state of the associated thread after hitting a + /// breakpoint (if that make sense for the architecture). Default + /// implementation simply returns true for architectures which do not + /// require any update. + /// + /// @return + /// True if the operation succeeded and false otherwise. + virtual bool UpdateAfterBreakpoint() = 0; - /// Determines the index in lldb's register file given a kernel byte offset. - virtual unsigned - GetRegisterIndexFromOffset(unsigned offset) = 0; + /// Determines the index in lldb's register file given a kernel byte offset. + virtual unsigned GetRegisterIndexFromOffset(unsigned offset) = 0; - // Checks to see if a watchpoint specified by hw_index caused the inferior - // to stop. - virtual bool - IsWatchpointHit (uint32_t hw_index) = 0; + // Checks to see if a watchpoint specified by hw_index caused the inferior + // to stop. + virtual bool IsWatchpointHit(uint32_t hw_index) = 0; - // Resets any watchpoints that have been hit. - virtual bool - ClearWatchpointHits () = 0; + // Resets any watchpoints that have been hit. + virtual bool ClearWatchpointHits() = 0; - // Returns the watchpoint address associated with a watchpoint hardware - // index. - virtual lldb::addr_t - GetWatchpointAddress (uint32_t hw_index) = 0; + // Returns the watchpoint address associated with a watchpoint hardware + // index. + virtual lldb::addr_t GetWatchpointAddress(uint32_t hw_index) = 0; - virtual bool - IsWatchpointVacant (uint32_t hw_index) = 0; + virtual bool IsWatchpointVacant(uint32_t hw_index) = 0; - virtual bool - SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) = 0; + virtual bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) = 0; - // From lldb_private::RegisterContext - virtual uint32_t - NumSupportedHardwareWatchpoints () = 0; + // From lldb_private::RegisterContext + virtual uint32_t NumSupportedHardwareWatchpoints() = 0; - // Force m_watchpoints_initialized to TRUE - void - ForceWatchpointsInitialized () {m_watchpoints_initialized = true;} + // Force m_watchpoints_initialized to TRUE + void ForceWatchpointsInitialized() { m_watchpoints_initialized = true; } protected: - bool m_watchpoints_initialized; + bool m_watchpoints_initialized; }; #endif // #ifndef liblldb_RegisterContextPOSIX_H_ - diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp index 9922311fd9db..f8d5f2edd3a3 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp @@ -11,312 +11,250 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" -#include "RegisterContextPOSIX_arm.h" #include "ProcessFreeBSD.h" -#include "RegisterContextPOSIXProcessMonitor_arm.h" #include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_arm.h" +#include "RegisterContextPOSIX_arm.h" using namespace lldb_private; using namespace lldb; #define REG_CONTEXT_SIZE (GetGPRSize()) -RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) -{ -} +RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm( + Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) {} -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_arm::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD*>(base.get()); - return process->GetMonitor(); +ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm::GetMonitor() { + ProcessSP base = CalculateProcess(); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); + return process->GetMonitor(); } -bool -RegisterContextPOSIXProcessMonitor_arm::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_arm::ReadGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_arm::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +bool RegisterContextPOSIXProcessMonitor_arm::ReadFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); } -bool -RegisterContextPOSIXProcessMonitor_arm::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_arm::WriteGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_arm::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); +bool RegisterContextPOSIXProcessMonitor_arm::WriteFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr)); } -bool -RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); +bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister( + const unsigned reg, RegisterValue &value) { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), + GetRegisterName(reg), GetRegisterSize(reg), + value); } -bool -RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } +bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister( + const unsigned reg, const RegisterValue &value) { + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData( + reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; } + } } + } - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), value_to_write); } -bool -RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - } - else - { - return ReadRegister(reg, value); - } +bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + if (!reg_info) + return false; - // Get pointer to m_fpr variable and set the data from it. - assert (reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; - } + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) { + if (!ReadFPR()) + return false; + } else { + return ReadRegister(reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert(reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } } -bool -RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; +bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsGPR(reg)) - { - return WriteRegister(reg, value); - } - else if (IsFPR(reg)) - { - return WriteFPR(); - } + if (IsGPR(reg)) { + return WriteRegister(reg, value); + } else if (IsFPR(reg)) { + return WriteFPR(); + } - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_arm, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy (dst, &m_fpr, sizeof(m_fpr)); - } +bool RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues( + DataBufferSP &data_sp) { + bool success = false; + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR() && ReadFPR()) { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) { + ::memcpy(dst, &m_gpr_arm, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr, sizeof(m_fpr)); } - return success; + } + return success; } -bool -RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_arm, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - ::memcpy (&m_fpr, src, sizeof(m_fpr)); - - success = WriteFPR(); - } - } +bool RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues( + const DataBufferSP &data_sp) { + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { + uint8_t *src = data_sp->GetBytes(); + if (src) { + ::memcpy(&m_gpr_arm, src, GetGPRSize()); + + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy(&m_fpr, src, sizeof(m_fpr)); + + success = WriteFPR(); + } } - return success; + } + return success; } -uint32_t -RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } +uint32_t RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint( + addr_t addr, size_t size, bool read, bool write) { + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); + } - return LLDB_INVALID_INDEX32; + return LLDB_INVALID_INDEX32; } -bool -RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() -{ - lldb::addr_t pc; +bool RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() { + lldb::addr_t pc; - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; - return true; + return true; } -unsigned -RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_arm; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm && "Invalid register offset."); - return reg; +unsigned RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset( + unsigned offset) { + unsigned reg; + for (reg = 0; reg < k_num_registers_arm; reg++) { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm && "Invalid register offset."); + return reg; } -bool -RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() { + return false; } -addr_t -RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; +addr_t RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress( + uint32_t hw_index) { + return LLDB_INVALID_ADDRESS; } -bool -RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex( + addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { + return false; } uint32_t -RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() -{ - return 0; +RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() { + return 0; } - diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h index 3787502a390c..6aa71c24f1cd 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h @@ -10,87 +10,68 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_ -#include "RegisterContextPOSIX.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h" +#include "RegisterContextPOSIX.h" -class RegisterContextPOSIXProcessMonitor_arm: - public RegisterContextPOSIX_arm, - public POSIXBreakpointProtocol -{ +class RegisterContextPOSIXProcessMonitor_arm : public RegisterContextPOSIX_arm, + public POSIXBreakpointProtocol { public: - RegisterContextPOSIXProcessMonitor_arm(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIXProcessMonitor_arm( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); protected: - bool - ReadGPR(); + bool ReadGPR(); - bool - ReadFPR(); + bool ReadFPR(); - bool - WriteGPR(); + bool WriteGPR(); - bool - WriteFPR(); + bool WriteFPR(); - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + // lldb_private::RegisterContext + bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + bool WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value); - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value); - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value); - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, + bool write); - bool - ClearHardwareWatchpoint(uint32_t hw_index); + bool ClearHardwareWatchpoint(uint32_t hw_index); - bool - HardwareSingleStep(bool enable); + bool HardwareSingleStep(bool enable); - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); + // POSIXBreakpointProtocol + bool UpdateAfterBreakpoint(); - unsigned - GetRegisterIndexFromOffset(unsigned offset); + unsigned GetRegisterIndexFromOffset(unsigned offset); - bool - IsWatchpointHit(uint32_t hw_index); + bool IsWatchpointHit(uint32_t hw_index); - bool - ClearWatchpointHits(); + bool ClearWatchpointHits(); - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); + lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - bool - IsWatchpointVacant(uint32_t hw_index); + bool IsWatchpointVacant(uint32_t hw_index); - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, + bool write, uint32_t hw_index); - uint32_t - NumSupportedHardwareWatchpoints(); + uint32_t NumSupportedHardwareWatchpoints(); private: - ProcessMonitor & - GetMonitor(); + ProcessMonitor &GetMonitor(); }; #endif diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp index a1a0cab82a15..98a213a370fe 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp @@ -21,298 +21,245 @@ using namespace lldb; using namespace lldb_private; -RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) -{ +RegisterContextPOSIXProcessMonitor_arm64:: + RegisterContextPOSIXProcessMonitor_arm64( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info) {} + +ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() { + lldb::ProcessSP base = CalculateProcess(); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); + return process->GetMonitor(); } -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() -{ - lldb::ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD*>(base.get()); - return process->GetMonitor(); +bool RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); } -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +bool RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); } -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr); +bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister( + const unsigned reg, lldb_private::RegisterValue &value) { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), + GetRegisterName(reg), GetRegisterSize(reg), + value); } -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg, - lldb_private::RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg, - const lldb_private::RegisterValue &value) -{ - unsigned reg_to_write = reg; - lldb_private::RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - lldb_private::RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - lldb_private::Error error; - lldb::ByteOrder byte_order = GetByteOrder(); - uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } +bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister( + const unsigned reg, const lldb_private::RegisterValue &value) { + unsigned reg_to_write = reg; + lldb_private::RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + lldb_private::RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const lldb_private::RegisterInfo *full_reg_info = + GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) { + lldb_private::Error error; + lldb::ByteOrder byte_order = GetByteOrder(); + uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData( + reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + ::memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; } + } } + } - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), value_to_write); } -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) -{ - if (!reg_info) - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister( + const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) { + if (!reg_info) + return false; - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - return ReadRegister(full_reg, value); - } + if (IsFPR(reg)) { + if (!ReadFPR()) + return false; + } else { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - // Get pointer to m_fpr variable and set the data from it. - assert (reg_info->byte_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; - switch (reg_info->byte_size) - { - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; + if (is_subreg) { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; } + return ReadRegister(full_reg, value); + } + + // Get pointer to m_fpr variable and set the data from it. + assert(reg_info->byte_offset < sizeof m_fpr); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } } -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; +bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister( + const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) { + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (IsGPR(reg)) - return WriteRegister(reg, value); + if (IsGPR(reg)) + return WriteRegister(reg, value); - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy (dst, &m_fpr, sizeof m_fpr); - } +bool RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + bool success = false; + data_sp.reset(new lldb_private::DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR() && ReadFPR()) { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) { + ::memcpy(dst, &m_gpr_arm64, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr, sizeof m_fpr); } - return success; + } + return success; } -bool -RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_arm64, src, GetGPRSize()); - if (WriteGPR()) { - src += GetGPRSize(); - ::memcpy (&m_fpr, src, sizeof m_fpr); - success = WriteFPR(); - } - } +bool RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { + uint8_t *src = data_sp->GetBytes(); + if (src) { + ::memcpy(&m_gpr_arm64, src, GetGPRSize()); + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy(&m_fpr, src, sizeof m_fpr); + success = WriteFPR(); + } } - return success; + } + return success; } -uint32_t -RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } +uint32_t RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, bool read, bool write) { + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); + } - return LLDB_INVALID_INDEX32; + return LLDB_INVALID_INDEX32; } -bool -RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() -{ - if (GetPC() == LLDB_INVALID_ADDRESS) - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() { + if (GetPC() == LLDB_INVALID_ADDRESS) + return false; - return true; + return true; } -unsigned -RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_arm64; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_arm64 && "Invalid register offset."); - return reg; +unsigned RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset( + unsigned offset) { + unsigned reg; + for (reg = 0; reg < k_num_registers_arm64; reg++) { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_arm64 && "Invalid register offset."); + return reg; } -bool -RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() { + return false; } -lldb::addr_t -RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; +lldb::addr_t RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress( + uint32_t hw_index) { + return LLDB_INVALID_ADDRESS; } -bool -RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex( + lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { + return false; } uint32_t -RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() -{ - return 0; +RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() { + return 0; } diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h index 729385c4a76e..8591c83be541 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h @@ -10,87 +10,69 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_ -#include "RegisterContextPOSIX.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" +#include "RegisterContextPOSIX.h" -class RegisterContextPOSIXProcessMonitor_arm64: - public RegisterContextPOSIX_arm64, - public POSIXBreakpointProtocol -{ +class RegisterContextPOSIXProcessMonitor_arm64 + : public RegisterContextPOSIX_arm64, + public POSIXBreakpointProtocol { public: - RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIXProcessMonitor_arm64( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); protected: - bool - ReadGPR(); + bool ReadGPR(); - bool - ReadFPR(); + bool ReadFPR(); - bool - WriteGPR(); + bool WriteGPR(); - bool - WriteFPR(); + bool WriteFPR(); - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + // lldb_private::RegisterContext + bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + bool WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value); - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value); - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value); - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, + bool write); - bool - ClearHardwareWatchpoint(uint32_t hw_index); + bool ClearHardwareWatchpoint(uint32_t hw_index); - bool - HardwareSingleStep(bool enable); + bool HardwareSingleStep(bool enable); - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); + // POSIXBreakpointProtocol + bool UpdateAfterBreakpoint(); - unsigned - GetRegisterIndexFromOffset(unsigned offset); + unsigned GetRegisterIndexFromOffset(unsigned offset); - bool - IsWatchpointHit(uint32_t hw_index); + bool IsWatchpointHit(uint32_t hw_index); - bool - ClearWatchpointHits(); + bool ClearWatchpointHits(); - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); + lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - bool - IsWatchpointVacant(uint32_t hw_index); + bool IsWatchpointVacant(uint32_t hw_index); - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, + bool write, uint32_t hw_index); - uint32_t - NumSupportedHardwareWatchpoints(); + uint32_t NumSupportedHardwareWatchpoints(); private: - ProcessMonitor & - GetMonitor(); + ProcessMonitor &GetMonitor(); }; #endif diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp index eeada4b16337..020636eb0a6b 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -1,11 +1,11 @@ -//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_mips64.cpp -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" @@ -21,298 +21,243 @@ using namespace lldb; #define REG_CONTEXT_SIZE (GetGPRSize()) -RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) -{ -} +RegisterContextPOSIXProcessMonitor_mips64:: + RegisterContextPOSIXProcessMonitor_mips64( + Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) {} -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD*>(base.get()); - return process->GetMonitor(); +ProcessMonitor &RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() { + ProcessSP base = CalculateProcess(); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); + return process->GetMonitor(); } -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() -{ - // XXX not yet implemented - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() { + // XXX not yet implemented + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() -{ - // XXX not yet implemented - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() { + // XXX not yet implemented + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); +bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister( + const unsigned reg, RegisterValue &value) { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), + GetRegisterName(reg), GetRegisterSize(reg), + value); } -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } +bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister( + const unsigned reg, const RegisterValue &value) { + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData( + reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; } + } } + } - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), value_to_write); } -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + if (!reg_info) + return false; - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; + if (IsFPR(reg)) { + if (!ReadFPR()) + return false; + } else { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - bool success = ReadRegister(full_reg, value); + bool success = ReadRegister(full_reg, value); - if (success) - { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); + if (success) { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value + // one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; + // If our return byte size was greater than the return value reg size, + // then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); } + return success; + } - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; +bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsGPR(reg)) - return WriteRegister(reg, value); + if (IsGPR(reg)) + return WriteRegister(reg, value); - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); - } +bool RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues( + DataBufferSP &data_sp) { + bool success = false; + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR() && ReadFPR()) { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) { + ::memcpy(dst, &m_gpr_mips64, GetGPRSize()); } - return success; + } + return success; } -bool -RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_mips64, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - } - } +bool RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues( + const DataBufferSP &data_sp) { + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { + uint8_t *src = data_sp->GetBytes(); + if (src) { + ::memcpy(&m_gpr_mips64, src, GetGPRSize()); + + if (WriteGPR()) { + src += GetGPRSize(); + } } - return success; + } + return success; } -uint32_t -RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } +uint32_t RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint( + addr_t addr, size_t size, bool read, bool write) { + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); + } - return LLDB_INVALID_INDEX32; + return LLDB_INVALID_INDEX32; } -bool -RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep( + bool enable) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; +bool RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() { + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; - SetPC(pc - 1); - return true; + SetPC(pc - 1); + return true; } -unsigned -RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_mips64; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_mips64 && "Invalid register offset."); - return reg; +unsigned RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset( + unsigned offset) { + unsigned reg; + for (reg = 0; reg < k_num_registers_mips64; reg++) { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_mips64 && "Invalid register offset."); + return reg; } -bool -RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() { + return false; } -addr_t -RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; +addr_t RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress( + uint32_t hw_index) { + return LLDB_INVALID_ADDRESS; } -bool -RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex( + addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { + return false; } uint32_t -RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() -{ - return 0; +RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() { + return 0; } - diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h index e61621bec197..2f75e6058fbc 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h @@ -10,87 +10,69 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ -#include "RegisterContextPOSIX.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h" +#include "RegisterContextPOSIX.h" -class RegisterContextPOSIXProcessMonitor_mips64: - public RegisterContextPOSIX_mips64, - public POSIXBreakpointProtocol -{ +class RegisterContextPOSIXProcessMonitor_mips64 + : public RegisterContextPOSIX_mips64, + public POSIXBreakpointProtocol { public: - RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIXProcessMonitor_mips64( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); protected: - bool - ReadGPR(); + bool ReadGPR(); - bool - ReadFPR(); + bool ReadFPR(); - bool - WriteGPR(); + bool WriteGPR(); - bool - WriteFPR(); + bool WriteFPR(); - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + // lldb_private::RegisterContext + bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + bool WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value); - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value); - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value); - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, + bool write); - bool - ClearHardwareWatchpoint(uint32_t hw_index); + bool ClearHardwareWatchpoint(uint32_t hw_index); - bool - HardwareSingleStep(bool enable); + bool HardwareSingleStep(bool enable); - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); + // POSIXBreakpointProtocol + bool UpdateAfterBreakpoint(); - unsigned - GetRegisterIndexFromOffset(unsigned offset); + unsigned GetRegisterIndexFromOffset(unsigned offset); - bool - IsWatchpointHit(uint32_t hw_index); + bool IsWatchpointHit(uint32_t hw_index); - bool - ClearWatchpointHits(); + bool ClearWatchpointHits(); - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); + lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - bool - IsWatchpointVacant(uint32_t hw_index); + bool IsWatchpointVacant(uint32_t hw_index); - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, + bool write, uint32_t hw_index); - uint32_t - NumSupportedHardwareWatchpoints(); + uint32_t NumSupportedHardwareWatchpoints(); private: - ProcessMonitor & - GetMonitor(); + ProcessMonitor &GetMonitor(); }; #endif diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp index 321e6ea262ce..e7b01fa8634a 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp @@ -1,337 +1,275 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_powerpc.cpp ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" -#include "RegisterContextPOSIX_powerpc.h" #include "ProcessFreeBSD.h" -#include "RegisterContextPOSIXProcessMonitor_powerpc.h" #include "ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_powerpc.h" +#include "RegisterContextPOSIX_powerpc.h" using namespace lldb_private; using namespace lldb; #define REG_CONTEXT_SIZE (GetGPRSize()) -RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) -{ -} +RegisterContextPOSIXProcessMonitor_powerpc:: + RegisterContextPOSIXProcessMonitor_powerpc( + Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) {} -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD*>(base.get()); - return process->GetMonitor(); +ProcessMonitor &RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() { + ProcessSP base = CalculateProcess(); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); + return process->GetMonitor(); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, + sizeof(m_fpr_powerpc)); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() -{ - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() { + // XXX: Need a way to read/write process VMX registers with ptrace. + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc)); +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, + sizeof(m_fpr_powerpc)); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() -{ - // XXX: Need a way to read/write process VMX registers with ptrace. - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() { + // XXX: Need a way to read/write process VMX registers with ptrace. + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister( + const unsigned reg, RegisterValue &value) { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), + GetRegisterName(reg), GetRegisterSize(reg), + value); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister( + const unsigned reg, const RegisterValue &value) { + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData( + reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; } + } } - - ProcessMonitor &monitor = GetMonitor(); - // Account for the fact that 32-bit targets on powerpc64 really use 64-bit - // registers in ptrace, but expose here 32-bit registers with a higher - // offset. - uint64_t offset = GetRegisterOffset(reg_to_write); - offset &= ~(sizeof(uintptr_t) - 1); - return monitor.WriteRegisterValue(m_thread.GetID(), - offset, - GetRegisterName(reg_to_write), - value_to_write); + } + + ProcessMonitor &monitor = GetMonitor(); + // Account for the fact that 32-bit targets on powerpc64 really use 64-bit + // registers in ptrace, but expose here 32-bit registers with a higher + // offset. + uint64_t offset = GetRegisterOffset(reg_to_write); + offset &= ~(sizeof(uintptr_t) - 1); + return monitor.WriteRegisterValue( + m_thread.GetID(), offset, GetRegisterName(reg_to_write), value_to_write); } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + if (!reg_info) + return false; - if (IsFPR(reg)) - { - if (!ReadFPR()) - return false; - uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - value.SetUInt64(*(uint64_t*)src); - } - else if (IsGPR(reg)) - { - bool success = ReadRegister(reg, value); - - if (success) - { - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) { + if (!ReadFPR()) + return false; + uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; + value.SetUInt64(*(uint64_t *)src); + } else if (IsGPR(reg)) { + bool success = ReadRegister(reg, value); + + if (success) { + // If our return byte size was greater than the return value reg size, + // then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); } + return success; + } - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsGPR(reg)) - { - return WriteRegister(reg, value); - } - else if (IsFPR(reg)) - { - assert (reg_info->byte_offset < sizeof(m_fpr_powerpc)); - uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; - *(uint64_t *)dst = value.GetAsUInt64(); - return WriteFPR(); - } + if (IsGPR(reg)) { + return WriteRegister(reg, value); + } else if (IsFPR(reg)) { + assert(reg_info->byte_offset < sizeof(m_fpr_powerpc)); + uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset; + *(uint64_t *)dst = value.GetAsUInt64(); + return WriteFPR(); + } - return false; + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) - { - ::memcpy (dst, &m_gpr_powerpc, GetGPRSize()); - dst += GetGPRSize(); - } +bool RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues( + DataBufferSP &data_sp) { + bool success = false; + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR() && ReadFPR()) { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) { + ::memcpy(dst, &m_gpr_powerpc, GetGPRSize()); + dst += GetGPRSize(); } - return success; + } + return success; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) - { - ::memcpy (&m_gpr_powerpc, src, GetGPRSize()); - - if (WriteGPR()) - { - src += GetGPRSize(); - ::memcpy (&m_fpr_powerpc, src, sizeof(m_fpr_powerpc)); - - success = WriteFPR(); - } - } +bool RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues( + const DataBufferSP &data_sp) { + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { + uint8_t *src = data_sp->GetBytes(); + if (src) { + ::memcpy(&m_gpr_powerpc, src, GetGPRSize()); + + if (WriteGPR()) { + src += GetGPRSize(); + ::memcpy(&m_fpr_powerpc, src, sizeof(m_fpr_powerpc)); + + success = WriteFPR(); + } } - return success; + } + return success; } -uint32_t -RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } +uint32_t RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint( + addr_t addr, size_t size, bool read, bool write) { + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; - return LLDB_INVALID_INDEX32; + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index); + } + + return LLDB_INVALID_INDEX32; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep( + bool enable) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() -{ - lldb::addr_t pc; +bool RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() { + lldb::addr_t pc; - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; - return true; + return true; } -unsigned -RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers_powerpc; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers_powerpc && "Invalid register offset."); - return reg; +unsigned RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset( + unsigned offset) { + unsigned reg; + for (reg = 0; reg < k_num_registers_powerpc; reg++) { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_powerpc && "Invalid register offset."); + return reg; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() { + return false; } -addr_t -RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index) -{ - return LLDB_INVALID_ADDRESS; +addr_t RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress( + uint32_t hw_index) { + return LLDB_INVALID_ADDRESS; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant( + uint32_t hw_index) { + return false; } -bool -RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - return false; +bool RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex( + addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) { + return false; } uint32_t -RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() -{ - return 0; +RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() { + return 0; } - diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h index ff1d0f36171b..188ddea7d473 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h @@ -1,4 +1,5 @@ -//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -10,96 +11,75 @@ #ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ #define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_ -#include "RegisterContextPOSIX.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "RegisterContextPOSIX.h" -class RegisterContextPOSIXProcessMonitor_powerpc: - public RegisterContextPOSIX_powerpc, - public POSIXBreakpointProtocol -{ +class RegisterContextPOSIXProcessMonitor_powerpc + : public RegisterContextPOSIX_powerpc, + public POSIXBreakpointProtocol { public: - RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIXProcessMonitor_powerpc( + lldb_private::Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info); protected: - bool - IsVMX(); + bool IsVMX(); - bool - ReadGPR(); + bool ReadGPR(); - bool - ReadFPR(); + bool ReadFPR(); - bool - ReadVMX(); + bool ReadVMX(); - bool - WriteGPR(); + bool WriteGPR(); - bool - WriteFPR(); + bool WriteFPR(); - bool - WriteVMX(); + bool WriteVMX(); - // lldb_private::RegisterContext - bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + // lldb_private::RegisterContext + bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + bool WriteRegister(const unsigned reg, + const lldb_private::RegisterValue &value); - bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value); - bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value); - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - uint32_t - SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, + bool write); - bool - ClearHardwareWatchpoint(uint32_t hw_index); + bool ClearHardwareWatchpoint(uint32_t hw_index); - bool - HardwareSingleStep(bool enable); + bool HardwareSingleStep(bool enable); - // POSIXBreakpointProtocol - bool - UpdateAfterBreakpoint(); + // POSIXBreakpointProtocol + bool UpdateAfterBreakpoint(); - unsigned - GetRegisterIndexFromOffset(unsigned offset); + unsigned GetRegisterIndexFromOffset(unsigned offset); - bool - IsWatchpointHit(uint32_t hw_index); + bool IsWatchpointHit(uint32_t hw_index); - bool - ClearWatchpointHits(); + bool ClearWatchpointHits(); - lldb::addr_t - GetWatchpointAddress(uint32_t hw_index); + lldb::addr_t GetWatchpointAddress(uint32_t hw_index); - bool - IsWatchpointVacant(uint32_t hw_index); + bool IsWatchpointVacant(uint32_t hw_index); - bool - SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, + bool write, uint32_t hw_index); - uint32_t - NumSupportedHardwareWatchpoints(); + uint32_t NumSupportedHardwareWatchpoints(); private: - ProcessMonitor & - GetMonitor(); + ProcessMonitor &GetMonitor(); }; #endif diff --git a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp index 31b9e7a38b21..976b190b2355 100644 --- a/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -1,673 +1,614 @@ -//===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- C++ -*-===// +//===-- RegisterContextPOSIXProcessMonitor_x86.cpp --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Target/Thread.h" #include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" -#include "RegisterContextPOSIXProcessMonitor_x86.h" #include "Plugins/Process/FreeBSD/ProcessMonitor.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" using namespace lldb_private; using namespace lldb; // Support ptrace extensions even when compiled without required kernel support #ifndef NT_X86_XSTATE - #define NT_X86_XSTATE 0x202 +#define NT_X86_XSTATE 0x202 #endif #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR)) -static uint32_t -size_and_rw_bits(size_t size, bool read, bool write) -{ - uint32_t rw; - - if (read) - rw = 0x3; // READ or READ/WRITE - else if (write) - rw = 0x1; // WRITE - else - assert(0 && "read and write cannot both be false"); - - switch (size) - { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - default: - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - return 0; // Unreachable. Just to silence compiler. - } +static uint32_t size_and_rw_bits(size_t size, bool read, bool write) { + uint32_t rw; + + if (read) + rw = 0x3; // READ or READ/WRITE + else if (write) + rw = 0x1; // WRITE + else + assert(0 && "read and write cannot both be false"); + + switch (size) { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + default: + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + return 0; // Unreachable. Just to silence compiler. + } } -RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) -{ - // Store byte offset of fctrl (i.e. first register of FPR) wrt 'UserArea' - const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl"); - m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; +RegisterContextPOSIXProcessMonitor_x86_64:: + RegisterContextPOSIXProcessMonitor_x86_64( + Thread &thread, uint32_t concrete_frame_idx, + lldb_private::RegisterInfoInterface *register_info) + : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) { + // Store byte offset of fctrl (i.e. first register of FPR) wrt 'UserArea' + const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl"); + m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; } -ProcessMonitor & -RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessFreeBSD *process = static_cast<ProcessFreeBSD*>(base.get()); - return process->GetMonitor(); +ProcessMonitor &RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() { + ProcessSP base = CalculateProcess(); + ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get()); + return process->GetMonitor(); } -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); +bool RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() { + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, + sizeof(m_fpr.xstate.fxsave)); - if (GetFPRType() == eXSAVE) - return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; + if (GetFPRType() == eXSAVE) + return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, + sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; } -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +bool RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() { + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); } -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (GetFPRType() == eFXSAVE) - return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); +bool RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() { + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, + sizeof(m_fpr.xstate.fxsave)); - if (GetFPRType() == eXSAVE) - return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; + if (GetFPRType() == eXSAVE) + return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, + sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; } -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); +bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( + const unsigned reg, RegisterValue &value) { + ProcessMonitor &monitor = GetMonitor(); #if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.ReadDebugRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); + if (reg >= m_reg_info.first_dr) + return monitor.ReadDebugRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg), GetRegisterName(reg), + GetRegisterSize(reg), value); #endif - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); + return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), + GetRegisterName(reg), GetRegisterSize(reg), + value); } -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - unsigned reg_to_write = reg; - RegisterValue value_to_write = value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) - { - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - if (ReadRegister(full_reg_info, full_value)) - { - Error error; - ByteOrder byte_order = GetByteOrder(); - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the full register. - const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, - dst, - sizeof(dst), - byte_order, - error); - if (error.Success() && dest_size) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Get the bytes for the source data. - const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); - if (error.Success() && src_size && (src_size < dest_size)) - { - // Copy the src bytes to the destination. - memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); - // Set this full register as the value to write. - value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); - value_to_write.SetType(full_reg_info); - reg_to_write = full_reg; - } - } +bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister( + const unsigned reg, const RegisterValue &value) { + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData( + full_reg_info, dst, sizeof(dst), byte_order, error); + if (error.Success() && dest_size) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData( + reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) { + // Copy the src bytes to the destination. + memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; } + } } + } - ProcessMonitor &monitor = GetMonitor(); + ProcessMonitor &monitor = GetMonitor(); #if defined(__FreeBSD__) - if (reg >= m_reg_info.first_dr) - return monitor.WriteDebugRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); + if (reg >= m_reg_info.first_dr) + return monitor.WriteDebugRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), value_to_write); #endif - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg_to_write), - GetRegisterName(reg_to_write), - value_to_write); + return monitor.WriteRegisterValue( + m_thread.GetID(), GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), value_to_write); } -bool -RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; +bool RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + if (!reg_info) + return false; - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsFPR(reg, GetFPRType())) - { - if (!ReadFPR()) - return false; + if (IsFPR(reg, GetFPRType())) { + if (!ReadFPR()) + return false; + } else { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && + (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; } - else - { - uint32_t full_reg = reg; - bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); - - if (is_subreg) - { - // Read the full aligned 64-bit register. - full_reg = reg_info->invalidate_regs[0]; - } - bool success = ReadRegister(full_reg, value); + bool success = ReadRegister(full_reg, value); - if (success) - { - // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. - if (is_subreg && (reg_info->byte_offset & 0x1)) - value.SetUInt64(value.GetAsUInt64() >> 8); + if (success) { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value + // one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); - } - return success; + // If our return byte size was greater than the return value reg size, + // then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); } + return success; + } + + if (reg_info->encoding == eEncodingVector) { + ByteOrder byte_order = GetByteOrder(); + + if (byte_order != ByteOrder::eByteOrderInvalid) { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + value.SetBytes( + m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, + reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + value.SetBytes( + m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, + reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + value.SetBytes( + m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, + reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { + // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) + value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + reg_info->byte_size, byte_order); + else + return false; + } + return value.GetType() == RegisterValue::eTypeBytes; + } + return false; + } + + // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. + // Byte offsets of all registers are calculated wrt 'UserArea' structure. + // However, ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)} + // and stores them in 'm_fpr' (of type FPR structure). To extract values of + // fpu + // registers, m_fpr should be read at byte offsets calculated wrt to FPR + // structure. + + // Since, FPR structure is also one of the member of UserArea structure. + // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - + // byte_offset(fctrl wrt UserArea) + assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr)); + uint8_t *src = + (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea; + switch (reg_info->byte_size) { + case 1: + value.SetUInt8(*(uint8_t *)src); + return true; + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} - if (reg_info->encoding == eEncodingVector) - { - ByteOrder byte_order = GetByteOrder(); - - if (byte_order != ByteOrder::eByteOrderInvalid) - { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) - { - // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes - if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) - value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); - else - return false; - } - return value.GetType() == RegisterValue::eTypeBytes; - } +bool RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + if (IsFPR(reg, GetFPRType())) { + if (reg_info->encoding == eEncodingVector) { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + ::memcpy(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, + value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + ::memcpy(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, + value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, + value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) { + if (GetFPRType() != eXSAVE) + return false; // the target processor does not support AVX + + // Store ymm register content, and split into the register halves in + // xmm.bytes and ymmh.bytes + ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + value.GetBytes(), value.GetByteSize()); + if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) + return false; + } + } else { + // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. + // Byte offsets of all registers are calculated wrt 'UserArea' structure. + // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only + // fpu + // registers using ptrace(PT_SETFPREGS,..) API. Hence fpu registers should + // be written in m_fpr at byte offsets calculated wrt FPR structure. + + // Since, FPR structure is also one of the member of UserArea structure. + // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - + // byte_offset(fctrl wrt UserArea) + assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < + sizeof(m_fpr)); + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - + m_fctrl_offset_in_userarea; + switch (reg_info->byte_size) { + case 1: + *(uint8_t *)dst = value.GetAsUInt8(); + break; + case 2: + *(uint16_t *)dst = value.GetAsUInt16(); + break; + case 4: + *(uint32_t *)dst = value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); return false; + } } - // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. - // Byte offsets of all registers are calculated wrt 'UserArea' structure. - // However, ReadFPR() reads fpu registers {using ptrace(PT_GETFPREGS,..)} - // and stores them in 'm_fpr' (of type FPR structure). To extract values of fpu - // registers, m_fpr should be read at byte offsets calculated wrt to FPR structure. - - // Since, FPR structure is also one of the member of UserArea structure. - // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea) - assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr)); - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea; - switch (reg_info->byte_size) - { - case 1: - value.SetUInt8(*(uint8_t *)src); - return true; - case 2: - value.SetUInt16(*(uint16_t *)src); - return true; - case 4: - value.SetUInt32(*(uint32_t *)src); - return true; - case 8: - value.SetUInt64(*(uint64_t *)src); - return true; - default: - assert(false && "Unhandled data size."); - return false; + if (WriteFPR()) { + if (IsAVX(reg)) + return CopyYMMtoXSTATE(reg, GetByteOrder()); + return true; } + } + return false; } -bool -RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsGPR(reg)) - return WriteRegister(reg, value); - - if (IsFPR(reg, GetFPRType())) - { - if (reg_info->encoding == eEncodingVector) - { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) - ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) - ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) - { - if (GetFPRType() != eXSAVE) - return false; // the target processor does not support AVX - - // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes - ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize()); - if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) - return false; - } - } - else - { - // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. - // Byte offsets of all registers are calculated wrt 'UserArea' structure. - // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only fpu - // registers using ptrace(PT_SETFPREGS,..) API. Hence fpu registers should - // be written in m_fpr at byte offsets calculated wrt FPR structure. - - // Since, FPR structure is also one of the member of UserArea structure. - // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea) - assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr)); - uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea; - switch (reg_info->byte_size) - { - case 1: - *(uint8_t *)dst = value.GetAsUInt8(); - break; - case 2: - *(uint16_t *)dst = value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return false; - } - } +bool RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues( + DataBufferSP &data_sp) { + bool success = false; + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR() && ReadFPR()) { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) { + ::memcpy(dst, &m_gpr_x86_64, GetGPRSize()); + dst += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy(dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + } - if (WriteFPR()) - { - |