diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
commit | 88c643b6fec27eec436c8d138fee6346e92337d6 (patch) | |
tree | 82cd13b2f3cde1c9e5f79689ba4e6ba67694843f /source/Plugins/Process | |
parent | 94994d372d014ce4c8758b9605d63fae651bd8aa (diff) |
Notes
Diffstat (limited to 'source/Plugins/Process')
75 files changed, 0 insertions, 19079 deletions
diff --git a/source/Plugins/Process/CMakeLists.txt b/source/Plugins/Process/CMakeLists.txt deleted file mode 100644 index fdeb211fe7a20..0000000000000 --- a/source/Plugins/Process/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android") - add_subdirectory(Linux) - add_subdirectory(POSIX) -elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - add_subdirectory(FreeBSD) - add_subdirectory(POSIX) -elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") - add_subdirectory(NetBSD) - add_subdirectory(POSIX) -elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") - add_subdirectory(Windows/Common) -elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") - add_subdirectory(MacOSX-Kernel) -endif() -add_subdirectory(gdb-remote) -add_subdirectory(Utility) -add_subdirectory(elf-core) -add_subdirectory(mach-core) -add_subdirectory(minidump) diff --git a/source/Plugins/Process/FreeBSD/CMakeLists.txt b/source/Plugins/Process/FreeBSD/CMakeLists.txt deleted file mode 100644 index c8301f350e076..0000000000000 --- a/source/Plugins/Process/FreeBSD/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_lldb_library(lldbPluginProcessFreeBSD PLUGIN - ProcessFreeBSD.cpp - FreeBSDThread.cpp - ProcessMonitor.cpp - - POSIXStopInfo.cpp - RegisterContextPOSIXProcessMonitor_arm.cpp - RegisterContextPOSIXProcessMonitor_arm64.cpp - RegisterContextPOSIXProcessMonitor_powerpc.cpp - RegisterContextPOSIXProcessMonitor_x86.cpp - RegisterContextPOSIXProcessMonitor_mips64.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbHost - lldbSymbol - lldbTarget - lldbUtility - lldbPluginProcessUtility - lldbPluginProcessPOSIX - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt deleted file mode 100644 index b4b4c401a271f..0000000000000 --- a/source/Plugins/Process/Linux/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_lldb_library(lldbPluginProcessLinux PLUGIN - NativeProcessLinux.cpp - NativeRegisterContextLinux.cpp - NativeRegisterContextLinux_arm.cpp - NativeRegisterContextLinux_arm64.cpp - NativeRegisterContextLinux_mips64.cpp - NativeRegisterContextLinux_ppc64le.cpp - NativeRegisterContextLinux_s390x.cpp - NativeRegisterContextLinux_x86_64.cpp - NativeThreadLinux.cpp - ProcessorTrace.cpp - SingleStepCheck.cpp - - LINK_LIBS - lldbCore - lldbHost - lldbSymbol - lldbTarget - lldbUtility - lldbPluginProcessPOSIX - lldbPluginProcessUtility - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp deleted file mode 100644 index 8c6c95380e814..0000000000000 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ /dev/null @@ -1,2097 +0,0 @@ -//===-- NativeProcessLinux.cpp -------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "NativeProcessLinux.h" - -#include <errno.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> - -#include <fstream> -#include <mutex> -#include <sstream> -#include <string> -#include <unordered_map> - -#include "lldb/Core/EmulateInstruction.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/PseudoTerminal.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/common/NativeRegisterContext.h" -#include "lldb/Host/linux/Ptrace.h" -#include "lldb/Host/linux/Uio.h" -#include "lldb/Host/posix/ProcessLauncherPosixFork.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/StringExtractor.h" -#include "llvm/Support/Errno.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Threading.h" - -#include "NativeThreadLinux.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/LinuxProcMaps.h" -#include "Procfs.h" - -#include <linux/unistd.h> -#include <sys/socket.h> -#include <sys/syscall.h> -#include <sys/types.h> -#include <sys/user.h> -#include <sys/wait.h> - -// Support hardware breakpoints in case it has not been defined -#ifndef TRAP_HWBKPT -#define TRAP_HWBKPT 4 -#endif - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; -using namespace llvm; - -// Private bits we only need internally. - -static bool ProcessVmReadvSupported() { - static bool is_supported; - static llvm::once_flag flag; - - llvm::call_once(flag, [] { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - uint32_t source = 0x47424742; - uint32_t dest = 0; - - struct iovec local, remote; - remote.iov_base = &source; - local.iov_base = &dest; - remote.iov_len = local.iov_len = sizeof source; - - // We shall try if cross-process-memory reads work by attempting to read a - // value from our own process. - ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); - is_supported = (res == sizeof(source) && source == dest); - if (is_supported) - LLDB_LOG(log, - "Detected kernel support for process_vm_readv syscall. " - "Fast memory reads enabled."); - else - LLDB_LOG(log, - "syscall process_vm_readv failed (error: {0}). Fast memory " - "reads disabled.", - llvm::sys::StrError()); - }); - - return is_supported; -} - -namespace { -void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - if (!log) - return; - - if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) - LLDB_LOG(log, "setting STDIN to '{0}'", action->GetFileSpec()); - else - LLDB_LOG(log, "leaving STDIN as is"); - - if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) - LLDB_LOG(log, "setting STDOUT to '{0}'", action->GetFileSpec()); - else - LLDB_LOG(log, "leaving STDOUT as is"); - - if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) - LLDB_LOG(log, "setting STDERR to '{0}'", action->GetFileSpec()); - else - LLDB_LOG(log, "leaving STDERR as is"); - - int i = 0; - for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; - ++args, ++i) - LLDB_LOG(log, "arg {0}: '{1}'", i, *args); -} - -void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { - uint8_t *ptr = (uint8_t *)bytes; - const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count); - for (uint32_t i = 0; i < loop_count; i++) { - s.Printf("[%x]", *ptr); - ptr++; - } -} - -void PtraceDisplayBytes(int &req, void *data, size_t data_size) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - if (!log) - return; - StreamString buf; - - switch (req) { - case PTRACE_POKETEXT: { - DisplayBytes(buf, &data, 8); - LLDB_LOGV(log, "PTRACE_POKETEXT {0}", buf.GetData()); - break; - } - case PTRACE_POKEDATA: { - DisplayBytes(buf, &data, 8); - LLDB_LOGV(log, "PTRACE_POKEDATA {0}", buf.GetData()); - break; - } - case PTRACE_POKEUSER: { - DisplayBytes(buf, &data, 8); - LLDB_LOGV(log, "PTRACE_POKEUSER {0}", buf.GetData()); - break; - } - case PTRACE_SETREGS: { - DisplayBytes(buf, data, data_size); - LLDB_LOGV(log, "PTRACE_SETREGS {0}", buf.GetData()); - break; - } - case PTRACE_SETFPREGS: { - DisplayBytes(buf, data, data_size); - LLDB_LOGV(log, "PTRACE_SETFPREGS {0}", buf.GetData()); - break; - } - case PTRACE_SETSIGINFO: { - DisplayBytes(buf, data, sizeof(siginfo_t)); - LLDB_LOGV(log, "PTRACE_SETSIGINFO {0}", buf.GetData()); - break; - } - case PTRACE_SETREGSET: { - // Extract iov_base from data, which is a pointer to the struct iovec - DisplayBytes(buf, *(void **)data, data_size); - LLDB_LOGV(log, "PTRACE_SETREGSET {0}", buf.GetData()); - break; - } - default: {} - } -} - -static constexpr unsigned k_ptrace_word_size = sizeof(void *); -static_assert(sizeof(long) >= k_ptrace_word_size, - "Size of long must be larger than ptrace word size"); -} // end of anonymous namespace - -// Simple helper function to ensure flags are enabled on the given file -// descriptor. -static Status EnsureFDFlags(int fd, int flags) { - Status error; - - int status = fcntl(fd, F_GETFL); - if (status == -1) { - error.SetErrorToErrno(); - return error; - } - - if (fcntl(fd, F_SETFL, status | flags) == -1) { - error.SetErrorToErrno(); - return error; - } - - return error; -} - -// ----------------------------------------------------------------------------- -// Public Static Methods -// ----------------------------------------------------------------------------- - -llvm::Expected<std::unique_ptr<NativeProcessProtocol>> -NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info, - NativeDelegate &native_delegate, - MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - MaybeLogLaunchInfo(launch_info); - - Status status; - ::pid_t pid = ProcessLauncherPosixFork() - .LaunchProcess(launch_info, status) - .GetProcessId(); - LLDB_LOG(log, "pid = {0:x}", pid); - if (status.Fail()) { - LLDB_LOG(log, "failed to launch process: {0}", status); - return status.ToError(); - } - - // Wait for the child process to trap on its call to execve. - int wstatus; - ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); - assert(wpid == pid); - (void)wpid; - if (!WIFSTOPPED(wstatus)) { - LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", - WaitStatus::Decode(wstatus)); - return llvm::make_error<StringError>("Could not sync with inferior process", - llvm::inconvertibleErrorCode()); - } - LLDB_LOG(log, "inferior started, now in stopped state"); - - ProcessInstanceInfo Info; - if (!Host::GetProcessInfo(pid, Info)) { - return llvm::make_error<StringError>("Cannot get process architecture", - llvm::inconvertibleErrorCode()); - } - - // Set the architecture to the exe architecture. - LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, - Info.GetArchitecture().GetArchitectureName()); - - status = SetDefaultPtraceOpts(pid); - if (status.Fail()) { - LLDB_LOG(log, "failed to set default ptrace options: {0}", status); - return status.ToError(); - } - - return std::unique_ptr<NativeProcessLinux>(new NativeProcessLinux( - pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, - Info.GetArchitecture(), mainloop, {pid})); -} - -llvm::Expected<std::unique_ptr<NativeProcessProtocol>> -NativeProcessLinux::Factory::Attach( - lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, - MainLoop &mainloop) const { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "pid = {0:x}", pid); - - // Retrieve the architecture for the running process. - ProcessInstanceInfo Info; - if (!Host::GetProcessInfo(pid, Info)) { - return llvm::make_error<StringError>("Cannot get process architecture", - llvm::inconvertibleErrorCode()); - } - - auto tids_or = NativeProcessLinux::Attach(pid); - if (!tids_or) - return tids_or.takeError(); - - return std::unique_ptr<NativeProcessLinux>(new NativeProcessLinux( - pid, -1, native_delegate, Info.GetArchitecture(), mainloop, *tids_or)); -} - -// ----------------------------------------------------------------------------- -// Public Instance Methods -// ----------------------------------------------------------------------------- - -NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, - NativeDelegate &delegate, - const ArchSpec &arch, MainLoop &mainloop, - llvm::ArrayRef<::pid_t> tids) - : NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) { - if (m_terminal_fd != -1) { - Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); - assert(status.Success()); - } - - Status status; - m_sigchld_handle = mainloop.RegisterSignal( - SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); - assert(m_sigchld_handle && status.Success()); - - for (const auto &tid : tids) { - NativeThreadLinux &thread = AddThread(tid); - thread.SetStoppedBySignal(SIGSTOP); - ThreadWasCreated(thread); - } - - // Let our process instance know the thread has stopped. - SetCurrentThreadID(tids[0]); - SetState(StateType::eStateStopped, false); - - // Proccess any signals we received before installing our handler - SigchldHandler(); -} - -llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - Status status; - // Use a map to keep track of the threads which we have attached/need to - // attach. - Host::TidMap tids_to_attach; - while (Host::FindProcessThreads(pid, tids_to_attach)) { - for (Host::TidMap::iterator it = tids_to_attach.begin(); - it != tids_to_attach.end();) { - if (it->second == false) { - lldb::tid_t tid = it->first; - - // Attach to the requested process. - // An attach will cause the thread to stop with a SIGSTOP. - if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) { - // No such thread. The thread may have exited. More error handling - // may be needed. - if (status.GetError() == ESRCH) { - it = tids_to_attach.erase(it); - continue; - } - return status.ToError(); - } - - int wpid = - llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL); - // Need to use __WALL otherwise we receive an error with errno=ECHLD At - // this point we should have a thread stopped if waitpid succeeds. - if (wpid < 0) { - // No such thread. The thread may have exited. More error handling - // may be needed. - if (errno == ESRCH) { - it = tids_to_attach.erase(it); - continue; - } - return llvm::errorCodeToError( - std::error_code(errno, std::generic_category())); - } - - if ((status = SetDefaultPtraceOpts(tid)).Fail()) - return status.ToError(); - - LLDB_LOG(log, "adding tid = {0}", tid); - it->second = true; - } - - // move the loop forward - ++it; - } - } - - size_t tid_count = tids_to_attach.size(); - if (tid_count == 0) - return llvm::make_error<StringError>("No such process", - llvm::inconvertibleErrorCode()); - - std::vector<::pid_t> tids; - tids.reserve(tid_count); - for (const auto &p : tids_to_attach) - tids.push_back(p.first); - return std::move(tids); -} - -Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { - long ptrace_opts = 0; - - // Have the child raise an event on exit. This is used to keep the child in - // limbo until it is destroyed. - ptrace_opts |= PTRACE_O_TRACEEXIT; - - // Have the tracer trace threads which spawn in the inferior process. - // TODO: if we want to support tracing the inferiors' child, add the - // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) - ptrace_opts |= PTRACE_O_TRACECLONE; - - // Have the tracer notify us before execve returns (needed to disable legacy - // SIGTRAP generation) - ptrace_opts |= PTRACE_O_TRACEEXEC; - - return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts); -} - -// Handles all waitpid events from the inferior process. -void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, - WaitStatus status) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - - // Certain activities differ based on whether the pid is the tid of the main - // thread. - const bool is_main_thread = (pid == GetID()); - - // Handle when the thread exits. - if (exited) { - LLDB_LOG(log, - "got exit signal({0}) , tid = {1} ({2} main thread), process " - "state = {3}", - signal, pid, is_main_thread ? "is" : "is not", GetState()); - - // This is a thread that exited. Ensure we're not tracking it anymore. - StopTrackingThread(pid); - - if (is_main_thread) { - // The main thread exited. We're done monitoring. Report to delegate. - SetExitStatus(status, true); - - // Notify delegate that our process has exited. - SetState(StateType::eStateExited, true); - } - return; - } - - siginfo_t info; - const auto info_err = GetSignalInfo(pid, &info); - auto thread_sp = GetThreadByID(pid); - - if (!thread_sp) { - // Normally, the only situation when we cannot find the thread is if we - // have just received a new thread notification. This is indicated by - // GetSignalInfo() returning si_code == SI_USER and si_pid == 0 - LLDB_LOG(log, "received notification about an unknown tid {0}.", pid); - - if (info_err.Fail()) { - LLDB_LOG(log, - "(tid {0}) GetSignalInfo failed ({1}). " - "Ingoring this notification.", - pid, info_err); - return; - } - - LLDB_LOG(log, "tid {0}, si_code: {1}, si_pid: {2}", pid, info.si_code, - info.si_pid); - - NativeThreadLinux &thread = AddThread(pid); - - // Resume the newly created thread. - ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(thread); - return; - } - - // Get details on the signal raised. - if (info_err.Success()) { - // We have retrieved the signal info. Dispatch appropriately. - if (info.si_signo == SIGTRAP) - MonitorSIGTRAP(info, *thread_sp); - else - MonitorSignal(info, *thread_sp, exited); - } else { - if (info_err.GetError() == EINVAL) { - // This is a group stop reception for this tid. We can reach here if we - // reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU into the tracee, - // triggering the group-stop mechanism. Normally receiving these would - // stop the process, pending a SIGCONT. Simulating this state in a - // debugger is hard and is generally not needed (one use case is - // debugging background task being managed by a shell). For general use, - // it is sufficient to stop the process in a signal-delivery stop which - // happens before the group stop. This done by MonitorSignal and works - // correctly for all signals. - LLDB_LOG(log, - "received a group stop for pid {0} tid {1}. Transparent " - "handling of group stops not supported, resuming the " - "thread.", - GetID(), pid); - ResumeThread(*thread_sp, thread_sp->GetState(), - LLDB_INVALID_SIGNAL_NUMBER); - } else { - // ptrace(GETSIGINFO) failed (but not due to group-stop). - - // A return value of ESRCH means the thread/process is no longer on the - // system, so it was killed somehow outside of our control. Either way, - // we can't do anything with it anymore. - - // Stop tracking the metadata for the thread since it's entirely off the - // system now. - const bool thread_found = StopTrackingThread(pid); - - LLDB_LOG(log, - "GetSignalInfo failed: {0}, tid = {1}, signal = {2}, " - "status = {3}, main_thread = {4}, thread_found: {5}", - info_err, pid, signal, status, is_main_thread, thread_found); - - if (is_main_thread) { - // Notify the delegate - our process is not available but appears to - // have been killed outside our control. Is eStateExited the right - // exit state in this case? - SetExitStatus(status, true); - SetState(StateType::eStateExited, true); - } else { - // This thread was pulled out from underneath us. Anything to do here? - // Do we want to do an all stop? - LLDB_LOG(log, - "pid {0} tid {1} non-main thread exit occurred, didn't " - "tell delegate anything since thread disappeared out " - "from underneath us", - GetID(), pid); - } - } - } -} - -void NativeProcessLinux::WaitForNewThread(::pid_t tid) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - if (GetThreadByID(tid)) { - // We are already tracking the thread - we got the event on the new thread - // (see MonitorSignal) before this one. We are done. - return; - } - - // The thread is not tracked yet, let's wait for it to appear. - int status = -1; - LLDB_LOG(log, - "received thread creation event for tid {0}. tid not tracked " - "yet, waiting for thread to appear...", - tid); - ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, __WALL); - // Since we are waiting on a specific tid, this must be the creation event. - // But let's do some checks just in case. - if (wait_pid != tid) { - LLDB_LOG(log, - "waiting for tid {0} failed. Assuming the thread has " - "disappeared in the meantime", - tid); - // The only way I know of this could happen is if the whole process was - // SIGKILLed in the mean time. In any case, we can't do anything about that - // now. - return; - } - if (WIFEXITED(status)) { - LLDB_LOG(log, - "waiting for tid {0} returned an 'exited' event. Not " - "tracking the thread.", - tid); - // Also a very improbable event. - return; - } - - LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid); - NativeThreadLinux &new_thread = AddThread(tid); - - ResumeThread(new_thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(new_thread); -} - -void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, - NativeThreadLinux &thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - const bool is_main_thread = (thread.GetID() == GetID()); - - assert(info.si_signo == SIGTRAP && "Unexpected child signal!"); - - switch (info.si_code) { - // TODO: these two cases are required if we want to support tracing of the - // inferiors' children. We'd need this to debug a monitor. case (SIGTRAP | - // (PTRACE_EVENT_FORK << 8)): case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): - - case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): { - // This is the notification on the parent thread which informs us of new - // thread creation. We don't want to do anything with the parent thread so - // we just resume it. In case we want to implement "break on thread - // creation" functionality, we would need to stop here. - - unsigned long event_message = 0; - if (GetEventMessage(thread.GetID(), &event_message).Fail()) { - LLDB_LOG(log, - "pid {0} received thread creation event but " - "GetEventMessage failed so we don't know the new tid", - thread.GetID()); - } else - WaitForNewThread(event_message); - - ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); - break; - } - - case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)): { - LLDB_LOG(log, "received exec event, code = {0}", info.si_code ^ SIGTRAP); - - // Exec clears any pending notifications. - m_pending_notification_tid = LLDB_INVALID_THREAD_ID; - - // Remove all but the main thread here. Linux fork creates a new process - // which only copies the main thread. - LLDB_LOG(log, "exec received, stop tracking all but main thread"); - - for (auto i = m_threads.begin(); i != m_threads.end();) { - if ((*i)->GetID() == GetID()) - i = m_threads.erase(i); - else - ++i; - } - assert(m_threads.size() == 1); - auto *main_thread = static_cast<NativeThreadLinux *>(m_threads[0].get()); - - SetCurrentThreadID(main_thread->GetID()); - main_thread->SetStoppedByExec(); - - // Tell coordinator about about the "new" (since exec) stopped main thread. - ThreadWasCreated(*main_thread); - - // Let our delegate know we have just exec'd. - NotifyDidExec(); - - // Let the process know we're stopped. - StopRunningThreads(main_thread->GetID()); - - break; - } - - case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): { - // The inferior process or one of its threads is about to exit. We don't - // want to do anything with the thread so we just resume it. In case we - // want to implement "break on thread exit" functionality, we would need to - // stop here. - - unsigned long data = 0; - if (GetEventMessage(thread.GetID(), &data).Fail()) - data = -1; - - LLDB_LOG(log, - "received PTRACE_EVENT_EXIT, data = {0:x}, WIFEXITED={1}, " - "WIFSIGNALED={2}, pid = {3}, main_thread = {4}", - data, WIFEXITED(data), WIFSIGNALED(data), thread.GetID(), - is_main_thread); - - - StateType state = thread.GetState(); - if (!StateIsRunningState(state)) { - // Due to a kernel bug, we may sometimes get this stop after the inferior - // gets a SIGKILL. This confuses our state tracking logic in - // ResumeThread(), since normally, we should not be receiving any ptrace - // events while the inferior is stopped. This makes sure that the - // inferior is resumed and exits normally. - state = eStateRunning; - } - ResumeThread(thread, state, LLDB_INVALID_SIGNAL_NUMBER); - - break; - } - - case 0: - case TRAP_TRACE: // We receive this on single stepping. - case TRAP_HWBKPT: // We receive this on watchpoint hit - { - // If a watchpoint was hit, report it - uint32_t wp_index; - Status error = thread.GetRegisterContext().GetWatchpointHitIndex( - wp_index, (uintptr_t)info.si_addr); - if (error.Fail()) - LLDB_LOG(log, - "received error while checking for watchpoint hits, pid = " - "{0}, error = {1}", - thread.GetID(), error); - if (wp_index != LLDB_INVALID_INDEX32) { - MonitorWatchpoint(thread, wp_index); - break; - } - - // If a breakpoint was hit, report it - uint32_t bp_index; - error = thread.GetRegisterContext().GetHardwareBreakHitIndex( - bp_index, (uintptr_t)info.si_addr); - if (error.Fail()) - LLDB_LOG(log, "received error while checking for hardware " - "breakpoint hits, pid = {0}, error = {1}", - thread.GetID(), error); - if (bp_index != LLDB_INVALID_INDEX32) { - MonitorBreakpoint(thread); - break; - } - - // Otherwise, report step over - MonitorTrace(thread); - break; - } - - case SI_KERNEL: -#if defined __mips__ - // For mips there is no special signal for watchpoint So we check for - // watchpoint in kernel trap - { - // If a watchpoint was hit, report it - uint32_t wp_index; - Status error = thread.GetRegisterContext().GetWatchpointHitIndex( - wp_index, LLDB_INVALID_ADDRESS); - if (error.Fail()) - LLDB_LOG(log, - "received error while checking for watchpoint hits, pid = " - "{0}, error = {1}", - thread.GetID(), error); - if (wp_index != LLDB_INVALID_INDEX32) { - MonitorWatchpoint(thread, wp_index); - break; - } - } -// NO BREAK -#endif - case TRAP_BRKPT: - MonitorBreakpoint(thread); - break; - - case SIGTRAP: - case (SIGTRAP | 0x80): - LLDB_LOG( - log, - "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}, resuming", - info.si_code, GetID(), thread.GetID()); - - // Ignore these signals until we know more about them. - ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); - break; - - default: - LLDB_LOG(log, "received unknown SIGTRAP stop event ({0}, pid {1} tid {2}", - info.si_code, GetID(), thread.GetID()); - MonitorSignal(info, thread, false); - break; - } -} - -void NativeProcessLinux::MonitorTrace(NativeThreadLinux &thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "received trace event, pid = {0}", thread.GetID()); - - // This thread is currently stopped. - thread.SetStoppedByTrace(); - - StopRunningThreads(thread.GetID()); -} - -void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) { - Log *log( - GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS)); - LLDB_LOG(log, "received breakpoint event, pid = {0}", thread.GetID()); - - // Mark the thread as stopped at breakpoint. - thread.SetStoppedByBreakpoint(); - FixupBreakpointPCAsNeeded(thread); - - if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != - m_threads_stepping_with_breakpoint.end()) - thread.SetStoppedByTrace(); - - StopRunningThreads(thread.GetID()); -} - -void NativeProcessLinux::MonitorWatchpoint(NativeThreadLinux &thread, - uint32_t wp_index) { - Log *log( - GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_WATCHPOINTS)); - LLDB_LOG(log, "received watchpoint event, pid = {0}, wp_index = {1}", - thread.GetID(), wp_index); - - // Mark the thread as stopped at watchpoint. The address is at - // (lldb::addr_t)info->si_addr if we need it. - thread.SetStoppedByWatchpoint(wp_index); - - // We need to tell all other running threads before we notify the delegate - // about this stop. - StopRunningThreads(thread.GetID()); -} - -void NativeProcessLinux::MonitorSignal(const siginfo_t &info, - NativeThreadLinux &thread, bool exited) { - const int signo = info.si_signo; - const bool is_from_llgs = info.si_pid == getpid(); - - 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 Linux. - // - // IOW, user generated signals never generate what we consider to be a - // "crash". - // - // Similarly, ACK signals generated by this monitor. - - // Handle the signal. - LLDB_LOG(log, - "received signal {0} ({1}) with code {2}, (siginfo pid = {3}, " - "waitpid pid = {4})", - Host::GetSignalAsCString(signo), signo, info.si_code, - thread.GetID()); - - // Check for thread stop notification. - if (is_from_llgs && (info.si_code == SI_TKILL) && (signo == SIGSTOP)) { - // This is a tgkill()-based stop. - LLDB_LOG(log, "pid {0} tid {1}, thread stopped", GetID(), thread.GetID()); - - // Check that we're not already marked with a stop reason. Note this thread - // really shouldn't already be marked as stopped - if we were, that would - // imply that the kernel signaled us with the thread stopping which we - // handled and marked as stopped, and that, without an intervening resume, - // we received another stop. It is more likely that we are missing the - // marking of a run state somewhere if we find that the thread was marked - // as stopped. - const StateType thread_state = thread.GetState(); - if (!StateIsStoppedState(thread_state, false)) { - // An inferior thread has stopped because of a SIGSTOP we have sent it. - // Generally, these are not important stops and we don't want to report - // them as they are just used to stop other threads when one thread (the - // one with the *real* stop reason) hits a breakpoint (watchpoint, - // etc...). However, in the case of an asynchronous Interrupt(), this - // *is* the real stop reason, so we leave the signal intact if this is - // the thread that was chosen as the triggering thread. - if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { - if (m_pending_notification_tid == thread.GetID()) - thread.SetStoppedBySignal(SIGSTOP, &info); - else - thread.SetStoppedWithNoReason(); - - SetCurrentThreadID(thread.GetID()); - SignalIfAllThreadsStopped(); - } else { - // We can end up here if stop was initiated by LLGS but by this time a - // thread stop has occurred - maybe initiated by another event. - Status error = ResumeThread(thread, thread.GetState(), 0); - if (error.Fail()) - LLDB_LOG(log, "failed to resume thread {0}: {1}", thread.GetID(), - error); - } - } else { - LLDB_LOG(log, - "pid {0} tid {1}, thread was already marked as a stopped " - "state (state={2}), leaving stop signal as is", - GetID(), thread.GetID(), thread_state); - SignalIfAllThreadsStopped(); - } - - // Done handling. - return; - } - - // Check if debugger should stop at this signal or just ignore it and resume - // the inferior. - if (m_signals_to_ignore.find(signo) != m_signals_to_ignore.end()) { - ResumeThread(thread, thread.GetState(), signo); - return; - } - - // This thread is stopped. - LLDB_LOG(log, "received signal {0}", Host::GetSignalAsCString(signo)); - thread.SetStoppedBySignal(signo, &info); - - // Send a stop to the debugger after we get all other threads to stop. - StopRunningThreads(thread.GetID()); -} - -namespace { - -struct EmulatorBaton { - NativeProcessLinux &m_process; - NativeRegisterContext &m_reg_context; - - // eRegisterKindDWARF -> RegsiterValue - std::unordered_map<uint32_t, RegisterValue> m_register_values; - - EmulatorBaton(NativeProcessLinux &process, NativeRegisterContext ®_context) - : m_process(process), m_reg_context(reg_context) {} -}; - -} // anonymous namespace - -static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, void *dst, size_t length) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - size_t bytes_read; - emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); - return bytes_read; -} - -static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, - const RegisterInfo *reg_info, - RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - auto it = emulator_baton->m_register_values.find( - reg_info->kinds[eRegisterKindDWARF]); - if (it != emulator_baton->m_register_values.end()) { - reg_value = it->second; - return true; - } - - // The emulator only fill in the dwarf regsiter numbers (and in some case the - // generic register numbers). Get the full register info from the register - // context based on the dwarf register numbers. - const RegisterInfo *full_reg_info = - emulator_baton->m_reg_context.GetRegisterInfo( - eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); - - Status error = - emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); - if (error.Success()) - return true; - - return false; -} - -static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - const RegisterInfo *reg_info, - const RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = - reg_value; - return true; -} - -static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, const void *dst, - size_t length) { - return length; -} - -static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { - const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - return regsiter_context.ReadRegisterAsUnsigned(flags_info, - LLDB_INVALID_ADDRESS); -} - -Status -NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { - Status error; - NativeRegisterContext& register_context = thread.GetRegisterContext(); - - std::unique_ptr<EmulateInstruction> emulator_ap( - EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, - nullptr)); - - if (emulator_ap == nullptr) - return Status("Instruction emulator not found!"); - - EmulatorBaton baton(*this, register_context); - emulator_ap->SetBaton(&baton); - emulator_ap->SetReadMemCallback(&ReadMemoryCallback); - emulator_ap->SetReadRegCallback(&ReadRegisterCallback); - emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); - emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); - - if (!emulator_ap->ReadInstruction()) - return Status("Read instruction failed!"); - - bool emulation_result = - emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); - - const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - - auto pc_it = - baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); - auto flags_it = - baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); - - lldb::addr_t next_pc; - lldb::addr_t next_flags; - if (emulation_result) { - assert(pc_it != baton.m_register_values.end() && - "Emulation was successfull but PC wasn't updated"); - next_pc = pc_it->second.GetAsUInt64(); - - if (flags_it != baton.m_register_values.end()) - next_flags = flags_it->second.GetAsUInt64(); - else - next_flags = ReadFlags(register_context); - } else if (pc_it == baton.m_register_values.end()) { - // Emulate instruction failed and it haven't changed PC. Advance PC with - // the size of the current opcode because the emulation of all - // PC modifying instruction should be successful. The failure most - // likely caused by a not supported instruction which don't modify PC. - next_pc = register_context.GetPC() + emulator_ap->GetOpcode().GetByteSize(); - next_flags = ReadFlags(register_context); - } else { - // The instruction emulation failed after it modified the PC. It is an - // unknown error where we can't continue because the next instruction is - // modifying the PC but we don't know how. - return Status("Instruction emulation failed unexpectedly."); - } - - if (m_arch.GetMachine() == llvm::Triple::arm) { - if (next_flags & 0x20) { - // Thumb mode - error = SetSoftwareBreakpoint(next_pc, 2); - } else { - // Arm mode - error = SetSoftwareBreakpoint(next_pc, 4); - } - } else if (m_arch.GetMachine() == llvm::Triple::mips64 || - m_arch.GetMachine() == llvm::Triple::mips64el || - m_arch.GetMachine() == llvm::Triple::mips || - m_arch.GetMachine() == llvm::Triple::mipsel || - m_arch.GetMachine() == llvm::Triple::ppc64le) - error = SetSoftwareBreakpoint(next_pc, 4); - else { - // No size hint is given for the next breakpoint - error = SetSoftwareBreakpoint(next_pc, 0); - } - - // If setting the breakpoint fails because next_pc is out of the address - // space, ignore it and let the debugee segfault. - if (error.GetError() == EIO || error.GetError() == EFAULT) { - return Status(); - } else if (error.Fail()) - return error; - - m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); - - return Status(); -} - -bool NativeProcessLinux::SupportHardwareSingleStepping() const { - if (m_arch.GetMachine() == llvm::Triple::arm || - m_arch.GetMachine() == llvm::Triple::mips64 || - m_arch.GetMachine() == llvm::Triple::mips64el || - m_arch.GetMachine() == llvm::Triple::mips || - m_arch.GetMachine() == llvm::Triple::mipsel) - return false; - return true; -} - -Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "pid {0}", GetID()); - - bool software_single_step = !SupportHardwareSingleStepping(); - - if (software_single_step) { - for (const auto &thread : m_threads) { - assert(thread && "thread list should not contain NULL threads"); - - const ResumeAction *const action = - resume_actions.GetActionForThread(thread->GetID(), true); - if (action == nullptr) - continue; - - if (action->state == eStateStepping) { - Status error = SetupSoftwareSingleStepping( - static_cast<NativeThreadLinux &>(*thread)); - if (error.Fail()) - return error; - } - } - } - - for (const auto &thread : m_threads) { - assert(thread && "thread list should not contain NULL threads"); - - const ResumeAction *const action = - resume_actions.GetActionForThread(thread->GetID(), true); - - if (action == nullptr) { - LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), - thread->GetID()); - continue; - } - - LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", - action->state, GetID(), thread->GetID()); - - switch (action->state) { - case eStateRunning: - case eStateStepping: { - // Run the thread, possibly feeding it the signal. - const int signo = action->signal; - ResumeThread(static_cast<NativeThreadLinux &>(*thread), action->state, - signo); - break; - } - - case eStateSuspended: - case eStateStopped: - llvm_unreachable("Unexpected state"); - - default: - return Status("NativeProcessLinux::%s (): unexpected state %s specified " - "for pid %" PRIu64 ", tid %" PRIu64, - __FUNCTION__, StateAsCString(action->state), GetID(), - thread->GetID()); - } - } - - return Status(); -} - -Status NativeProcessLinux::Halt() { - Status error; - - if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); - - return error; -} - -Status NativeProcessLinux::Detach() { - Status error; - - // Stop monitoring the inferior. - m_sigchld_handle.reset(); - - // Tell ptrace to detach from the process. - if (GetID() == LLDB_INVALID_PROCESS_ID) - return error; - - for (const auto &thread : m_threads) { - Status e = Detach(thread->GetID()); - if (e.Fail()) - error = - e; // Save the error, but still attempt to detach from other threads. - } - - m_processor_trace_monitor.clear(); - m_pt_proces_trace_id = LLDB_INVALID_UID; - - return error; -} - -Status NativeProcessLinux::Signal(int signo) { - Status error; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "sending signal {0} ({1}) to pid {1}", signo, - Host::GetSignalAsCString(signo), GetID()); - - if (kill(GetID(), signo)) - error.SetErrorToErrno(); - - return error; -} - -Status NativeProcessLinux::Interrupt() { - // Pick a running thread (or if none, a not-dead stopped thread) as the - // chosen thread that will be the stop-reason thread. - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - NativeThreadProtocol *running_thread = nullptr; - NativeThreadProtocol *stopped_thread = nullptr; - - LLDB_LOG(log, "selecting running thread for interrupt target"); - for (const auto &thread : m_threads) { - // If we have a running or stepping thread, we'll call that the target of - // the interrupt. - const auto thread_state = thread->GetState(); - if (thread_state == eStateRunning || thread_state == eStateStepping) { - running_thread = thread.get(); - break; - } else if (!stopped_thread && StateIsStoppedState(thread_state, true)) { - // Remember the first non-dead stopped thread. We'll use that as a - // backup if there are no running threads. - stopped_thread = thread.get(); - } - } - - if (!running_thread && !stopped_thread) { - Status error("found no running/stepping or live stopped threads as target " - "for interrupt"); - LLDB_LOG(log, "skipping due to error: {0}", error); - - return error; - } - - NativeThreadProtocol *deferred_signal_thread = - running_thread ? running_thread : stopped_thread; - - LLDB_LOG(log, "pid {0} {1} tid {2} chosen for interrupt target", GetID(), - running_thread ? "running" : "stopped", - deferred_signal_thread->GetID()); - - StopRunningThreads(deferred_signal_thread->GetID()); - - return Status(); -} - -Status NativeProcessLinux::Kill() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "pid {0}", GetID()); - - Status error; - - switch (m_state) { - case StateType::eStateInvalid: - case StateType::eStateExited: - case StateType::eStateCrashed: - case StateType::eStateDetached: - case StateType::eStateUnloaded: - // Nothing to do - the process is already dead. - LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), - m_state); - return error; - - case StateType::eStateConnected: - case StateType::eStateAttaching: - case StateType::eStateLaunching: - case StateType::eStateStopped: - case StateType::eStateRunning: - case StateType::eStateStepping: - case StateType::eStateSuspended: - // We can try to kill a process in these states. - break; - } - - if (kill(GetID(), SIGKILL) != 0) { - error.SetErrorToErrno(); - return error; - } - - return error; -} - -Status NativeProcessLinux::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) { - // FIXME review that the final memory region returned extends to the end of - // the virtual address space, - // with no perms if it is not mapped. - - // Use an approach that reads memory regions from /proc/{pid}/maps. Assume - // proc maps entries are in ascending order. - // FIXME assert if we find differently. - - if (m_supports_mem_region == LazyBool::eLazyBoolNo) { - // We're done. - return Status("unsupported"); - } - - Status error = PopulateMemoryRegionCache(); - if (error.Fail()) { - return error; - } - - lldb::addr_t prev_base_address = 0; - - // FIXME start by finding the last region that is <= target address using - // binary search. Data is sorted. - // There can be a ton of regions on pthreads apps with lots of threads. - for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); - ++it) { - MemoryRegionInfo &proc_entry_info = it->first; - - // Sanity check assumption that /proc/{pid}/maps entries are ascending. - assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && - "descending /proc/pid/maps entries detected, unexpected"); - prev_base_address = proc_entry_info.GetRange().GetRangeBase(); - UNUSED_IF_ASSERT_DISABLED(prev_base_address); - - // If the target address comes before this entry, indicate distance to next - // region. - if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { - range_info.GetRange().SetRangeBase(load_addr); - range_info.GetRange().SetByteSize( - proc_entry_info.GetRange().GetRangeBase() - load_addr); - range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); - - return error; - } else if (proc_entry_info.GetRange().Contains(load_addr)) { - // The target address is within the memory region we're processing here. - range_info = proc_entry_info; - return error; - } - - // The target memory address comes somewhere after the region we just - // parsed. - } - - // If we made it here, we didn't find an entry that contained the given - // address. Return the load_addr as start and the amount of bytes betwwen - // load address and the end of the memory as size. - range_info.GetRange().SetRangeBase(load_addr); - range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); - range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); - range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); - return error; -} - -Status NativeProcessLinux::PopulateMemoryRegionCache() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - - // If our cache is empty, pull the latest. There should always be at least - // one memory region if memory region handling is supported. - if (!m_mem_region_cache.empty()) { - LLDB_LOG(log, "reusing {0} cached memory region entries", - m_mem_region_cache.size()); - return Status(); - } - - auto BufferOrError = getProcFile(GetID(), "maps"); - if (!BufferOrError) { - m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); - } - Status Result; - ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), - [&](const MemoryRegionInfo &Info, const Status &ST) { - if (ST.Success()) { - FileSpec file_spec(Info.GetName().GetCString()); - FileSystem::Instance().Resolve(file_spec); - m_mem_region_cache.emplace_back(Info, file_spec); - return true; - } else { - m_supports_mem_region = LazyBool::eLazyBoolNo; - LLDB_LOG(log, "failed to parse proc maps: {0}", ST); - Result = ST; - return false; - } - }); - if (Result.Fail()) - return Result; - - if (m_mem_region_cache.empty()) { - // No entries after attempting to read them. This shouldn't happen if - // /proc/{pid}/maps is supported. Assume we don't support map entries via - // procfs. - m_supports_mem_region = LazyBool::eLazyBoolNo; - LLDB_LOG(log, - "failed to find any procfs maps entries, assuming no support " - "for memory region metadata retrieval"); - return Status("not supported"); - } - - LLDB_LOG(log, "read {0} memory region entries from /proc/{1}/maps", - m_mem_region_cache.size(), GetID()); - - // We support memory retrieval, remember that. - m_supports_mem_region = LazyBool::eLazyBoolYes; - return Status(); -} - -void NativeProcessLinux::DoStopIDBumped(uint32_t newBumpId) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "newBumpId={0}", newBumpId); - LLDB_LOG(log, "clearing {0} entries from memory region cache", - m_mem_region_cache.size()); - m_mem_region_cache.clear(); -} - -Status NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { -// FIXME implementing this requires the equivalent of -// InferiorCallPOSIX::InferiorCallMmap, which depends on functional ThreadPlans -// working with Native*Protocol. -#if 1 - return Status("not implemented yet"); -#else - 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; - - // TODO implement this directly in NativeProcessLinux - // (and lift to NativeProcessPOSIX if/when that class is refactored out). - if (InferiorCallMmap(this, addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { - m_addr_to_mmap_size[addr] = size; - return Status(); - } else { - addr = LLDB_INVALID_ADDRESS; - return Status("unable to allocate %" PRIu64 - " bytes of memory with permissions %s", - size, GetPermissionsAsCString(permissions)); - } -#endif -} - -Status NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) { - // FIXME see comments in AllocateMemory - required lower-level - // bits not in place yet (ThreadPlans) - return Status("not implemented"); -} - -lldb::addr_t NativeProcessLinux::GetSharedLibraryInfoAddress() { - // punt on this for now - return LLDB_INVALID_ADDRESS; -} - -size_t NativeProcessLinux::UpdateThreads() { - // The NativeProcessLinux monitoring threads are always up to date with - // respect to thread state and they keep the thread list populated properly. - // All this method needs to do is return the thread count. - return m_threads.size(); -} - -Status NativeProcessLinux::SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) { - if (hardware) - return SetHardwareBreakpoint(addr, size); - else - return SetSoftwareBreakpoint(addr, size); -} - -Status NativeProcessLinux::RemoveBreakpoint(lldb::addr_t addr, bool hardware) { - if (hardware) - return RemoveHardwareBreakpoint(addr); - else - return NativeProcessProtocol::RemoveBreakpoint(addr); -} - -llvm::Expected<llvm::ArrayRef<uint8_t>> -NativeProcessLinux::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the - // linux kernel does otherwise. - static const uint8_t g_arm_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; - static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; - - switch (GetArchitecture().GetMachine()) { - case llvm::Triple::arm: - switch (size_hint) { - case 2: - return llvm::makeArrayRef(g_thumb_opcode); - case 4: - return llvm::makeArrayRef(g_arm_opcode); - default: - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Unrecognised trap opcode size hint!"); - } - default: - return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); - } -} - -Status NativeProcessLinux::ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) { - if (ProcessVmReadvSupported()) { - // The process_vm_readv path is about 50 times faster than ptrace api. We - // want to use this syscall if it is supported. - - const ::pid_t pid = GetID(); - - struct iovec local_iov, remote_iov; - local_iov.iov_base = buf; - local_iov.iov_len = size; - remote_iov.iov_base = reinterpret_cast<void *>(addr); - remote_iov.iov_len = size; - - bytes_read = process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0); - const bool success = bytes_read == size; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, - "using process_vm_readv to read {0} bytes from inferior " - "address {1:x}: {2}", - size, addr, success ? "Success" : llvm::sys::StrError(errno)); - - if (success) - return Status(); - // else the call failed for some reason, let's retry the read using ptrace - // api. - } - - unsigned char *dst = static_cast<unsigned char *>(buf); - size_t remainder; - long data; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); - LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); - - for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_PEEKDATA, GetID(), (void *)addr, nullptr, 0, &data); - if (error.Fail()) - return error; - - remainder = size - bytes_read; - remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; - - // Copy the data into our buffer - memcpy(dst, &data, remainder); - - LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); - addr += k_ptrace_word_size; - dst += k_ptrace_word_size; - } - return Status(); -} - -Status NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, - size_t size, size_t &bytes_written) { - const unsigned char *src = static_cast<const unsigned char *>(buf); - size_t remainder; - Status error; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); - LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); - - for (bytes_written = 0; bytes_written < size; bytes_written += remainder) { - remainder = size - bytes_written; - remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; - - if (remainder == k_ptrace_word_size) { - unsigned long data = 0; - memcpy(&data, src, k_ptrace_word_size); - - LLDB_LOG(log, "[{0:x}]:{1:x}", addr, data); - error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, GetID(), - (void *)addr, (void *)data); - if (error.Fail()) - return error; - } else { - unsigned char buff[8]; - size_t bytes_read; - error = ReadMemory(addr, buff, k_ptrace_word_size, bytes_read); - if (error.Fail()) - return error; - - memcpy(buff, src, remainder); - - size_t bytes_written_rec; - error = WriteMemory(addr, buff, k_ptrace_word_size, bytes_written_rec); - if (error.Fail()) - return error; - - LLDB_LOG(log, "[{0:x}]:{1:x} ({2:x})", addr, *(const unsigned long *)src, - *(unsigned long *)buff); - } - - addr += k_ptrace_word_size; - src += k_ptrace_word_size; - } - return error; -} - -Status NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) { - return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); -} - -Status NativeProcessLinux::GetEventMessage(lldb::tid_t tid, - unsigned long *message) { - return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); -} - -Status NativeProcessLinux::Detach(lldb::tid_t tid) { - if (tid == LLDB_INVALID_THREAD_ID) - return Status(); - - return PtraceWrapper(PTRACE_DETACH, tid); -} - -bool NativeProcessLinux::HasThreadNoLock(lldb::tid_t thread_id) { - for (const auto &thread : m_threads) { - assert(thread && "thread list should not contain NULL threads"); - if (thread->GetID() == thread_id) { - // We have this thread. - return true; - } - } - - // We don't have this thread. - return false; -} - -bool NativeProcessLinux::StopTrackingThread(lldb::tid_t thread_id) { - Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - LLDB_LOG(log, "tid: {0})", thread_id); - - bool found = false; - for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { - if (*it && ((*it)->GetID() == thread_id)) { - m_threads.erase(it); - found = true; - break; - } - } - - if (found) - StopTracingForThread(thread_id); - SignalIfAllThreadsStopped(); - return found; -} - -NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); - - assert(!HasThreadNoLock(thread_id) && - "attempted to add a thread by id that already exists"); - - // If this is the first thread, save it as the current thread - if (m_threads.empty()) - SetCurrentThreadID(thread_id); - - m_threads.push_back(llvm::make_unique<NativeThreadLinux>(*this, thread_id)); - - if (m_pt_proces_trace_id != LLDB_INVALID_UID) { - auto traceMonitor = ProcessorTraceMonitor::Create( - GetID(), thread_id, m_pt_process_trace_config, true); - if (traceMonitor) { - m_pt_traced_thread_group.insert(thread_id); - m_processor_trace_monitor.insert( - std::make_pair(thread_id, std::move(*traceMonitor))); - } else { - LLDB_LOG(log, "failed to start trace on thread {0}", thread_id); - Status error(traceMonitor.takeError()); - LLDB_LOG(log, "error {0}", error); - } - } - - return static_cast<NativeThreadLinux &>(*m_threads.back()); -} - -Status NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) { - Status error = PopulateMemoryRegionCache(); - if (error.Fail()) - return error; - - FileSpec module_file_spec(module_path); - FileSystem::Instance().Resolve(module_file_spec); - - file_spec.Clear(); - for (const auto &it : m_mem_region_cache) { - if (it.second.GetFilename() == module_file_spec.GetFilename()) { - file_spec = it.second; - return Status(); - } - } - return Status("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", - module_file_spec.GetFilename().AsCString(), GetID()); -} - -Status NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) { - load_addr = LLDB_INVALID_ADDRESS; - Status error = PopulateMemoryRegionCache(); - if (error.Fail()) - return error; - - FileSpec file(file_name); - for (const auto &it : m_mem_region_cache) { - if (it.second == file) { - load_addr = it.first.GetRange().GetRangeBase(); - return Status(); - } - } - return Status("No load address found for specified file."); -} - -NativeThreadLinux *NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { - return static_cast<NativeThreadLinux *>( - NativeProcessProtocol::GetThreadByID(tid)); -} - -Status NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, - lldb::StateType state, int signo) { - Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - LLDB_LOG(log, "tid: {0}", thread.GetID()); - - // Before we do the resume below, first check if we have a pending stop - // notification that is currently waiting for all threads to stop. This is - // potentially a buggy situation since we're ostensibly waiting for threads - // to stop before we send out the pending notification, and here we are - // resuming one before we send out the pending stop notification. - if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { - LLDB_LOG(log, - "about to resume tid {0} per explicit request but we have a " - "pending stop notification (tid {1}) that is actively " - "waiting for this thread to stop. Valid sequence of events?", - thread.GetID(), m_pending_notification_tid); - } - - // Request a resume. We expect this to be synchronous and the system to - // reflect it is running after this completes. - switch (state) { - case eStateRunning: { - const auto resume_result = thread.Resume(signo); - if (resume_result.Success()) - SetState(eStateRunning, true); - return resume_result; - } - case eStateStepping: { - const auto step_result = thread.SingleStep(signo); - if (step_result.Success()) - SetState(eStateRunning, true); - return step_result; - } - default: - LLDB_LOG(log, "Unhandled state {0}.", state); - llvm_unreachable("Unhandled state for resume"); - } -} - -//===----------------------------------------------------------------------===// - -void NativeProcessLinux::StopRunningThreads(const lldb::tid_t triggering_tid) { - Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - LLDB_LOG(log, "about to process event: (triggering_tid: {0})", - triggering_tid); - - m_pending_notification_tid = triggering_tid; - - // Request a stop for all the thread stops that need to be stopped and are - // not already known to be stopped. - for (const auto &thread : m_threads) { - if (StateIsRunningState(thread->GetState())) - static_cast<NativeThreadLinux *>(thread.get())->RequestStop(); - } - - SignalIfAllThreadsStopped(); - LLDB_LOG(log, "event processing done"); -} - -void NativeProcessLinux::SignalIfAllThreadsStopped() { - if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) - return; // No pending notification. Nothing to do. - - for (const auto &thread_sp : m_threads) { - if (StateIsRunningState(thread_sp->GetState())) - return; // Some threads are still running. Don't signal yet. - } - - // We have a pending notification and all threads have stopped. - Log *log( - GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS)); - - // Clear any temporary breakpoints we used to implement software single - // stepping. - for (const auto &thread_info : m_threads_stepping_with_breakpoint) { - Status error = RemoveBreakpoint(thread_info.second); - if (error.Fail()) - LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", - thread_info.first, error); - } - m_threads_stepping_with_breakpoint.clear(); - - // Notify the delegate about the stop - SetCurrentThreadID(m_pending_notification_tid); - SetState(StateType::eStateStopped, true); - m_pending_notification_tid = LLDB_INVALID_THREAD_ID; -} - -void NativeProcessLinux::ThreadWasCreated(NativeThreadLinux &thread) { - Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - LLDB_LOG(log, "tid: {0}", thread.GetID()); - - if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && - StateIsRunningState(thread.GetState())) { - // We will need to wait for this new thread to stop as well before firing - // the notification. - thread.RequestStop(); - } -} - -void NativeProcessLinux::SigchldHandler() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - // Process all pending waitpid notifications. - while (true) { - int status = -1; - ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, - __WALL | __WNOTHREAD | WNOHANG); - - if (wait_pid == 0) - break; // We are done. - - if (wait_pid == -1) { - Status error(errno, eErrorTypePOSIX); - LLDB_LOG(log, "waitpid (-1, &status, _) failed: {0}", error); - break; - } - - WaitStatus wait_status = WaitStatus::Decode(status); - bool exited = wait_status.type == WaitStatus::Exit || - (wait_status.type == WaitStatus::Signal && - wait_pid == static_cast<::pid_t>(GetID())); - - LLDB_LOG( - log, - "waitpid (-1, &status, _) => pid = {0}, status = {1}, exited = {2}", - wait_pid, wait_status, exited); - - MonitorCallback(wait_pid, exited, wait_status); - } -} - -// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets -// errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) -Status NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, - void *data, size_t data_size, - long *result) { - Status error; - long int ret; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - PtraceDisplayBytes(req, data, data_size); - - errno = 0; - if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET) - ret = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), - *(unsigned int *)addr, data); - else - ret = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), - addr, data); - - if (ret == -1) - error.SetErrorToErrno(); - - if (result) - *result = ret; - - LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data, - data_size, ret); - - PtraceDisplayBytes(req, data, data_size); - - if (error.Fail()) - LLDB_LOG(log, "ptrace() failed: {0}", error); - - return error; -} - -llvm::Expected<ProcessorTraceMonitor &> -NativeProcessLinux::LookupProcessorTraceInstance(lldb::user_id_t traceid, - lldb::tid_t thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - if (thread == LLDB_INVALID_THREAD_ID && traceid == m_pt_proces_trace_id) { - LLDB_LOG(log, "thread not specified: {0}", traceid); - return Status("tracing not active thread not specified").ToError(); - } - - for (auto& iter : m_processor_trace_monitor) { - if (traceid == iter.second->GetTraceID() && - (thread == iter.first || thread == LLDB_INVALID_THREAD_ID)) - return *(iter.second); - } - - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - return Status("tracing not active for this thread").ToError(); -} - -Status NativeProcessLinux::GetMetaData(lldb::user_id_t traceid, - lldb::tid_t thread, - llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset) { - TraceOptions trace_options; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - - LLDB_LOG(log, "traceid {0}", traceid); - - auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); - if (!perf_monitor) { - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - buffer = buffer.slice(buffer.size()); - error = perf_monitor.takeError(); - return error; - } - return (*perf_monitor).ReadPerfTraceData(buffer, offset); -} - -Status NativeProcessLinux::GetData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - - LLDB_LOG(log, "traceid {0}", traceid); - - auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); - if (!perf_monitor) { - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - buffer = buffer.slice(buffer.size()); - error = perf_monitor.takeError(); - return error; - } - return (*perf_monitor).ReadPerfTraceAux(buffer, offset); -} - -Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid, - TraceOptions &config) { - Status error; - if (config.getThreadID() == LLDB_INVALID_THREAD_ID && - m_pt_proces_trace_id == traceid) { - if (m_pt_proces_trace_id == LLDB_INVALID_UID) { - error.SetErrorString("tracing not active for this process"); - return error; - } - config = m_pt_process_trace_config; - } else { - auto perf_monitor = - LookupProcessorTraceInstance(traceid, config.getThreadID()); - if (!perf_monitor) { - error = perf_monitor.takeError(); - return error; - } - error = (*perf_monitor).GetTraceConfig(config); - } - return error; -} - -lldb::user_id_t -NativeProcessLinux::StartTraceGroup(const TraceOptions &config, - Status &error) { - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - if (config.getType() != TraceType::eTraceTypeProcessorTrace) - return LLDB_INVALID_UID; - - if (m_pt_proces_trace_id != LLDB_INVALID_UID) { - error.SetErrorString("tracing already active on this process"); - return m_pt_proces_trace_id; - } - - for (const auto &thread_sp : m_threads) { - if (auto traceInstance = ProcessorTraceMonitor::Create( - GetID(), thread_sp->GetID(), config, true)) { - m_pt_traced_thread_group.insert(thread_sp->GetID()); - m_processor_trace_monitor.insert( - std::make_pair(thread_sp->GetID(), std::move(*traceInstance))); - } - } - - m_pt_process_trace_config = config; - error = ProcessorTraceMonitor::GetCPUType(m_pt_process_trace_config); - - // Trace on Complete process will have traceid of 0 - m_pt_proces_trace_id = 0; - - LLDB_LOG(log, "Process Trace ID {0}", m_pt_proces_trace_id); - return m_pt_proces_trace_id; -} - -lldb::user_id_t NativeProcessLinux::StartTrace(const TraceOptions &config, - Status &error) { - if (config.getType() != TraceType::eTraceTypeProcessorTrace) - return NativeProcessProtocol::StartTrace(config, error); - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - lldb::tid_t threadid = config.getThreadID(); - - if (threadid == LLDB_INVALID_THREAD_ID) - return StartTraceGroup(config, error); - - auto thread_sp = GetThreadByID(threadid); - if (!thread_sp) { - // Thread not tracked by lldb so don't trace. - error.SetErrorString("invalid thread id"); - return LLDB_INVALID_UID; - } - - const auto &iter = m_processor_trace_monitor.find(threadid); - if (iter != m_processor_trace_monitor.end()) { - LLDB_LOG(log, "Thread already being traced"); - error.SetErrorString("tracing already active on this thread"); - return LLDB_INVALID_UID; - } - - auto traceMonitor = - ProcessorTraceMonitor::Create(GetID(), threadid, config, false); - if (!traceMonitor) { - error = traceMonitor.takeError(); - LLDB_LOG(log, "error {0}", error); - return LLDB_INVALID_UID; - } - lldb::user_id_t ret_trace_id = (*traceMonitor)->GetTraceID(); - m_processor_trace_monitor.insert( - std::make_pair(threadid, std::move(*traceMonitor))); - return ret_trace_id; -} - -Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) { - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - LLDB_LOG(log, "Thread {0}", thread); - - const auto& iter = m_processor_trace_monitor.find(thread); - if (iter == m_processor_trace_monitor.end()) { - error.SetErrorString("tracing not active for this thread"); - return error; - } - - if (iter->second->GetTraceID() == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the thread - // group. - LLDB_LOG(log, "traceid maps to process"); - m_pt_traced_thread_group.erase(thread); - } - m_processor_trace_monitor.erase(iter); - - return error; -} - -Status NativeProcessLinux::StopTrace(lldb::user_id_t traceid, - lldb::tid_t thread) { - Status error; - - TraceOptions trace_options; - trace_options.setThreadID(thread); - error = NativeProcessLinux::GetTraceConfig(traceid, trace_options); - - if (error.Fail()) - return error; - - switch (trace_options.getType()) { - case lldb::TraceType::eTraceTypeProcessorTrace: - if (traceid == m_pt_proces_trace_id && - thread == LLDB_INVALID_THREAD_ID) - StopProcessorTracingOnProcess(); - else - error = StopProcessorTracingOnThread(traceid, thread); - break; - default: - error.SetErrorString("trace not supported"); - break; - } - - return error; -} - -void NativeProcessLinux::StopProcessorTracingOnProcess() { - for (auto thread_id_iter : m_pt_traced_thread_group) - m_processor_trace_monitor.erase(thread_id_iter); - m_pt_traced_thread_group.clear(); - m_pt_proces_trace_id = LLDB_INVALID_UID; -} - -Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid, - lldb::tid_t thread) { - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - if (thread == LLDB_INVALID_THREAD_ID) { - for (auto& iter : m_processor_trace_monitor) { - if (iter.second->GetTraceID() == traceid) { - // Stopping a trace instance for an individual thread hence there will - // only be one traceid that can match. - m_processor_trace_monitor.erase(iter.first); - return error; - } - LLDB_LOG(log, "Trace ID {0}", iter.second->GetTraceID()); - } - - LLDB_LOG(log, "Invalid TraceID"); - error.SetErrorString("invalid trace id"); - return error; - } - - // thread is specified so we can use find function on the map. - const auto& iter = m_processor_trace_monitor.find(thread); - if (iter == m_processor_trace_monitor.end()) { - // thread not found in our map. - LLDB_LOG(log, "thread not being traced"); - error.SetErrorString("tracing not active for this thread"); - return error; - } - if (iter->second->GetTraceID() != traceid) { - // traceid did not match so it has to be invalid. - LLDB_LOG(log, "Invalid TraceID"); - error.SetErrorString("invalid trace id"); - return error; - } - - LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread); - - if (traceid == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the thread - // group. - LLDB_LOG(log, "traceid maps to process"); - m_pt_traced_thread_group.erase(thread); - } - m_processor_trace_monitor.erase(iter); - - return error; -} diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h deleted file mode 100644 index 69f2b528d3300..0000000000000 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ /dev/null @@ -1,261 +0,0 @@ -//===-- NativeProcessLinux.h ---------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_NativeProcessLinux_H_ -#define liblldb_NativeProcessLinux_H_ - -#include <csignal> -#include <unordered_set> - -#include "lldb/Host/Debug.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/linux/Support.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/lldb-types.h" - -#include "NativeThreadLinux.h" -#include "ProcessorTrace.h" -#include "lldb/Host/common/NativeProcessProtocol.h" - -namespace lldb_private { -class Status; -class Scalar; - -namespace process_linux { -/// @class NativeProcessLinux -/// 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 NativeProcessLinux : public NativeProcessProtocol { -public: - class Factory : public NativeProcessProtocol::Factory { - public: - llvm::Expected<std::unique_ptr<NativeProcessProtocol>> - Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, - MainLoop &mainloop) const override; - - llvm::Expected<std::unique_ptr<NativeProcessProtocol>> - Attach(lldb::pid_t pid, NativeDelegate &native_delegate, - MainLoop &mainloop) const override; - }; - - // --------------------------------------------------------------------- - // NativeProcessProtocol Interface - // --------------------------------------------------------------------- - Status Resume(const ResumeActionList &resume_actions) override; - - Status Halt() override; - - Status Detach() override; - - Status Signal(int signo) override; - - Status Interrupt() override; - - Status Kill() override; - - Status GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) override; - - Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, - size_t &bytes_read) override; - - Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, - size_t &bytes_written) override; - - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Status DeallocateMemory(lldb::addr_t addr) override; - - lldb::addr_t GetSharedLibraryInfoAddress() override; - - size_t UpdateThreads() override; - - const ArchSpec &GetArchitecture() const override { return m_arch; } - - Status SetBreakpoint(lldb::addr_t addr, uint32_t size, - bool hardware) override; - - Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override; - - void DoStopIDBumped(uint32_t newBumpId) override; - - Status GetLoadedModuleFileSpec(const char *module_path, - FileSpec &file_spec) override; - - Status GetFileLoadAddress(const llvm::StringRef &file_name, - lldb::addr_t &load_addr) override; - - NativeThreadLinux *GetThreadByID(lldb::tid_t id); - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> - GetAuxvData() const override { - return getProcFile(GetID(), "auxv"); - } - - lldb::user_id_t StartTrace(const TraceOptions &config, - Status &error) override; - - Status StopTrace(lldb::user_id_t traceid, - lldb::tid_t thread) override; - - Status GetData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset = 0) override; - - Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset = 0) override; - - Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override; - - // --------------------------------------------------------------------- - // Interface used by NativeRegisterContext-derived classes. - // --------------------------------------------------------------------- - static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, - void *data = nullptr, size_t data_size = 0, - long *result = nullptr); - - bool SupportHardwareSingleStepping() const; - -protected: - llvm::Expected<llvm::ArrayRef<uint8_t>> - GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; - -private: - MainLoop::SignalHandleUP m_sigchld_handle; - ArchSpec m_arch; - - LazyBool m_supports_mem_region = eLazyBoolCalculate; - std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache; - - lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; - - // 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; - - // --------------------------------------------------------------------- - // Private Instance Methods - // --------------------------------------------------------------------- - NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, - const ArchSpec &arch, MainLoop &mainloop, - llvm::ArrayRef<::pid_t> tids); - - // Returns a list of process threads that we have attached to. - static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid); - - static Status SetDefaultPtraceOpts(const lldb::pid_t); - - void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status); - - void WaitForNewThread(::pid_t tid); - - void MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread); - - void MonitorTrace(NativeThreadLinux &thread); - - void MonitorBreakpoint(NativeThreadLinux &thread); - - void MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index); - - void MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, - bool exited); - - Status SetupSoftwareSingleStepping(NativeThreadLinux &thread); - - bool HasThreadNoLock(lldb::tid_t thread_id); - - bool StopTrackingThread(lldb::tid_t thread_id); - - NativeThreadLinux &AddThread(lldb::tid_t thread_id); - - /// Writes a siginfo_t structure corresponding to the given thread ID to the - /// memory region pointed to by @p siginfo. - Status GetSignalInfo(lldb::tid_t tid, void *siginfo); - - /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG) - /// corresponding to the given thread ID to the memory pointed to by @p - /// message. - Status GetEventMessage(lldb::tid_t tid, unsigned long *message); - - void NotifyThreadDeath(lldb::tid_t tid); - - Status Detach(lldb::tid_t tid); - - // This method is requests a stop on all threads which are still running. It - // sets up a - // deferred delegate notification, which will fire once threads report as - // stopped. The - // triggerring_tid will be set as the current thread (main stop reason). - void StopRunningThreads(lldb::tid_t triggering_tid); - - // Notify the delegate if all threads have stopped. - void SignalIfAllThreadsStopped(); - - // Resume the given thread, optionally passing it the given signal. The type - // of resume - // operation (continue, single-step) depends on the state parameter. - Status ResumeThread(NativeThreadLinux &thread, lldb::StateType state, - int signo); - - void ThreadWasCreated(NativeThreadLinux &thread); - - void SigchldHandler(); - - Status PopulateMemoryRegionCache(); - - lldb::user_id_t StartTraceGroup(const TraceOptions &config, - Status &error); - - // This function is intended to be used to stop tracing - // on a thread that exited. - Status StopTracingForThread(lldb::tid_t thread); - - // The below function as the name suggests, looks up a ProcessorTrace - // instance from the m_processor_trace_monitor map. In the case of - // process tracing where the traceid passed would map to the complete - // process, it is mandatory to provide a threadid to obtain a trace - // instance (since ProcessorTrace is tied to a thread). In the other - // scenario that an individual thread is being traced, just the traceid - // is sufficient to obtain the actual ProcessorTrace instance. - llvm::Expected<ProcessorTraceMonitor &> - LookupProcessorTraceInstance(lldb::user_id_t traceid, lldb::tid_t thread); - - // Stops tracing on individual threads being traced. Not intended - // to be used to stop tracing on complete process. - Status StopProcessorTracingOnThread(lldb::user_id_t traceid, - lldb::tid_t thread); - - // Intended to stop tracing on complete process. - // Should not be used for stopping trace on - // individual threads. - void StopProcessorTracingOnProcess(); - - llvm::DenseMap<lldb::tid_t, ProcessorTraceMonitorUP> - m_processor_trace_monitor; - - // Set for tracking threads being traced under - // same process user id. - llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group; - - lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID; - TraceOptions m_pt_process_trace_config; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef liblldb_NativeProcessLinux_H_ diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp deleted file mode 100644 index 79f635c88985b..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ /dev/null @@ -1,196 +0,0 @@ -//===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "NativeRegisterContextLinux.h" - -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/Host/linux/Ptrace.h" -#include "lldb/Utility/RegisterValue.h" - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -NativeRegisterContextLinux::NativeRegisterContextLinux( - NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {} - -lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { - return m_thread.GetProcess().GetByteOrder(); -} - -Status NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, - RegisterValue ®_value) { - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); - - return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, - reg_info->byte_size, reg_value); -} - -Status -NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, - const RegisterValue ®_value) { - uint32_t reg_to_write = reg_index; - RegisterValue value_to_write = reg_value; - - // Check if this is a subregister of a full register. - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); - if (reg_info->invalidate_regs && - (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { - Status error; - - RegisterValue full_value; - uint32_t full_reg = reg_info->invalidate_regs[0]; - const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); - - // Read the full register. - error = ReadRegister(full_reg_info, full_value); - if (error.Fail()) - return error; - - lldb::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 = reg_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; - } - } - } - - const RegisterInfo *const register_to_write_info_p = - GetRegisterInfoAtIndex(reg_to_write); - assert(register_to_write_info_p && - "register to write does not have valid RegisterInfo"); - if (!register_to_write_info_p) - return Status("NativeRegisterContextLinux::%s failed to get RegisterInfo " - "for write register index %" PRIu32, - __FUNCTION__, reg_to_write); - - return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); -} - -Status NativeRegisterContextLinux::ReadGPR() { - void *buf = GetGPRBuffer(); - if (!buf) - return Status("GPR buffer is NULL"); - size_t buf_size = GetGPRSize(); - - return DoReadGPR(buf, buf_size); -} - -Status NativeRegisterContextLinux::WriteGPR() { - void *buf = GetGPRBuffer(); - if (!buf) - return Status("GPR buffer is NULL"); - size_t buf_size = GetGPRSize(); - - return DoWriteGPR(buf, buf_size); -} - -Status NativeRegisterContextLinux::ReadFPR() { - void *buf = GetFPRBuffer(); - if (!buf) - return Status("FPR buffer is NULL"); - size_t buf_size = GetFPRSize(); - - return DoReadFPR(buf, buf_size); -} - -Status NativeRegisterContextLinux::WriteFPR() { - void *buf = GetFPRBuffer(); - if (!buf) - return Status("FPR buffer is NULL"); - size_t buf_size = GetFPRSize(); - - return DoWriteFPR(buf, buf_size); -} - -Status NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, - unsigned int regset) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), - static_cast<void *>(®set), buf, - buf_size); -} - -Status NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, - unsigned int regset) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - static_cast<void *>(®set), buf, - buf_size); -} - -Status NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, - const char *reg_name, - uint32_t size, - RegisterValue &value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); - - long data; - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), - nullptr, 0, &data); - - if (error.Success()) - // First cast to an unsigned of the same size to avoid sign extension. - value.SetUInt(static_cast<unsigned long>(data), size); - - LLDB_LOG(log, "{0}: {1:x}", reg_name, data); - return error; -} - -Status NativeRegisterContextLinux::DoWriteRegisterValue( - uint32_t offset, const char *reg_name, const RegisterValue &value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); - - void *buf = reinterpret_cast<void *>(value.GetAsUInt64()); - LLDB_LOG(log, "{0}: {1}", reg_name, buf); - - return NativeProcessLinux::PtraceWrapper( - PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf); -} - -Status NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), - nullptr, buf, buf_size); -} - -Status NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), - nullptr, buf, buf_size); -} - -Status NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), - nullptr, buf, buf_size); -} - -Status NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), - nullptr, buf, buf_size); -} diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux.h deleted file mode 100644 index 2cea497b53bcd..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.h +++ /dev/null @@ -1,85 +0,0 @@ -//===-- NativeRegisterContextLinux.h ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_NativeRegisterContextLinux_h -#define lldb_NativeRegisterContextLinux_h - -#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" -#include "lldb/Host/common/NativeThreadProtocol.h" - -namespace lldb_private { -namespace process_linux { - -class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo { -public: - NativeRegisterContextLinux(NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p); - - // This function is implemented in the NativeRegisterContextLinux_* subclasses - // to create a new instance of the host specific NativeRegisterContextLinux. - // The implementations can't collide as only one NativeRegisterContextLinux_* - // variant should be compiled into the final executable. - static std::unique_ptr<NativeRegisterContextLinux> - CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - -protected: - lldb::ByteOrder GetByteOrder() const; - - virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); - - virtual Status WriteRegisterRaw(uint32_t reg_index, - const RegisterValue ®_value); - - virtual Status ReadRegisterSet(void *buf, size_t buf_size, - unsigned int regset); - - virtual Status WriteRegisterSet(void *buf, size_t buf_size, - unsigned int regset); - - virtual Status ReadGPR(); - - virtual Status WriteGPR(); - - virtual Status ReadFPR(); - - virtual Status WriteFPR(); - - virtual void *GetGPRBuffer() { return nullptr; } - - virtual size_t GetGPRSize() { - return GetRegisterInfoInterface().GetGPRSize(); - } - - virtual void *GetFPRBuffer() { return nullptr; } - - virtual size_t GetFPRSize() { return 0; } - - // The Do*** functions are executed on the privileged thread and can perform - // ptrace - // operations directly. - virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name, - uint32_t size, RegisterValue &value); - - virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, - const RegisterValue &value); - - virtual Status DoReadGPR(void *buf, size_t buf_size); - - virtual Status DoWriteGPR(void *buf, size_t buf_size); - - virtual Status DoReadFPR(void *buf, size_t buf_size); - - virtual Status DoWriteFPR(void *buf, size_t buf_size); -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_h diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp deleted file mode 100644 index 09d3a12942f05..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ /dev/null @@ -1,975 +0,0 @@ -//===-- NativeRegisterContextLinux_arm.cpp --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - -#include "NativeRegisterContextLinux_arm.h" - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include <elf.h> -#include <sys/socket.h> - -#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr)) - -#ifndef PTRACE_GETVFPREGS -#define PTRACE_GETVFPREGS 27 -#define PTRACE_SETVFPREGS 28 -#endif -#ifndef PTRACE_GETHBPREGS -#define PTRACE_GETHBPREGS 29 -#define PTRACE_SETHBPREGS 30 -#endif -#if !defined(PTRACE_TYPE_ARG3) -#define PTRACE_TYPE_ARG3 void * -#endif -#if !defined(PTRACE_TYPE_ARG4) -#define PTRACE_TYPE_ARG4 void * -#endif - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -// arm general purpose registers. -static const uint32_t g_gpr_regnums_arm[] = { - gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, - gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, - gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, - gpr_pc_arm, gpr_cpsr_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == - k_num_gpr_registers_arm, - "g_gpr_regnums_arm has wrong number of register infos"); - -// arm floating point registers. -static const uint32_t g_fpu_regnums_arm[] = { - fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, - fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, - fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, - fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, - fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, - fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, - fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, - fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, - fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, - fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, - fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, - fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, - fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, - fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, - fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, - fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, - fpu_q15_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == - k_num_fpr_registers_arm, - "g_fpu_regnums_arm has wrong number of register infos"); - -namespace { -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; -} - -// Register sets for arm. -static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, - g_gpr_regnums_arm}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, - g_fpu_regnums_arm}}; - -#if defined(__arm__) - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return llvm::make_unique<NativeRegisterContextLinux_arm>(target_arch, - native_thread); -} - -#endif // defined(__arm__) - -NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_arm(target_arch)) { - switch (target_arch.GetMachine()) { - case llvm::Triple::arm: - m_reg_info.num_registers = k_num_registers_arm; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; - m_reg_info.last_gpr = k_last_gpr_arm; - m_reg_info.first_fpr = k_first_fpr_arm; - m_reg_info.last_fpr = k_last_fpr_arm; - m_reg_info.first_fpr_v = fpu_s0_arm; - m_reg_info.last_fpr_v = fpu_s31_arm; - m_reg_info.gpr_flags = gpr_cpsr_arm; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - ::memset(&m_fpr, 0, sizeof(m_fpr)); - ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm)); - ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); - ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); - - // 16 is just a maximum value, query hardware for actual watchpoint count - m_max_hwp_supported = 16; - m_max_hbp_supported = 16; - m_refresh_hwdebug_info = true; -} - -uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const { - return k_num_register_sets; -} - -uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) - count += g_reg_sets_arm[set_index].num_registers; - return count; -} - -const RegisterSet * -NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const { - if (set_index < k_num_register_sets) - return &g_reg_sets_arm[set_index]; - - return nullptr; -} - -Status -NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsFPR(reg)) { - error = ReadFPR(); - if (error.Fail()) - return error; - } 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]; - } - - error = ReadRegisterRaw(full_reg, reg_value); - - if (error.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)) - reg_value.SetUInt64(reg_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 (reg_value.GetByteSize() > reg_info->byte_size) - reg_value.SetType(reg_info); - } - return error; - } - - // Get pointer to m_fpr variable and set the data from it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; - switch (reg_info->byte_size) { - case 2: - reg_value.SetUInt16(*(uint16_t *)src); - break; - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - case 16: - reg_value.SetBytes(src, 16, GetByteOrder()); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - - return error; -} - -Status -NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - if (IsGPR(reg_index)) - return WriteRegisterRaw(reg_index, reg_value); - - if (IsFPR(reg_index)) { - // Get pointer to m_fpr variable and set the data to it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < sizeof m_fpr); - uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; - switch (reg_info->byte_size) { - case 2: - *(uint16_t *)dst = reg_value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled register data size %" PRIu32, - reg_info->byte_size); - } - - Status error = WriteFPR(); - if (error.Fail()) - return error; - - return Status(); - } - - return Status("failed - register wasn't recognized to be a GPR or an FPR, " - "write strategy unknown"); -} - -Status NativeRegisterContextLinux_arm::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) - return Status("failed to allocate DataBufferHeap instance of size %" PRIu64, - (uint64_t)REG_CONTEXT_SIZE); - - error = ReadGPR(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - (uint64_t)REG_CONTEXT_SIZE); - return error; - } - - ::memcpy(dst, &m_gpr_arm, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, &m_fpr, sizeof(m_fpr)); - - return error; -} - -Status NativeRegisterContextLinux_arm::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize()); - - error = WriteGPR(); - if (error.Fail()) - return error; - - src += GetRegisterInfoInterface().GetGPRSize(); - ::memcpy(&m_fpr, src, sizeof(m_fpr)); - - error = WriteFPR(); - if (error.Fail()) - return error; - - return error; -} - -bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const { - return reg <= m_reg_info.last_gpr; // GPR's come first. -} - -bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); -} - -uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); - - Status error; - - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - LLDB_LOG(log, "{0}", m_max_hbp_supported); - return m_max_hbp_supported; -} - -uint32_t -NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, bp_index = 0; - - // Setup address and control values. - // Use size to get a hint of arm vs thumb modes. - switch (size) { - case 2: - control_value = (0x3 << 5) | 7; - addr &= ~1; - break; - case 4: - control_value = (0xfu << 5) | 7; - addr &= ~3; - break; - default: - return LLDB_INVALID_INDEX32; - } - - // Iterate over stored breakpoints and find a free bp_index - bp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if ((m_hbr_regs[i].control & 1) == 0) { - bp_index = i; // Mark last free slot - } else if (m_hbr_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. - } - } - - if (bp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update breakpoint in local cache - m_hbr_regs[bp_index].real_addr = addr; - m_hbr_regs[bp_index].address = addr; - m_hbr_regs[bp_index].control = control_value; - - // PTRACE call to set corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); - - if (error.Fail()) { - m_hbr_regs[bp_index].address = 0; - m_hbr_regs[bp_index].control &= ~1; - - return LLDB_INVALID_INDEX32; - } - - return bp_index; -} - -bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "hw_idx: {0}", hw_idx); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return false; - - if (hw_idx >= m_max_hbp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; - uint32_t tempControl = m_hbr_regs[hw_idx].control; - - m_hbr_regs[hw_idx].control &= ~1; - m_hbr_regs[hw_idx].address = 0; - - // PTRACE call to clear corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); - - if (error.Fail()) { - m_hbr_regs[hw_idx].control = tempControl; - m_hbr_regs[hw_idx].address = tempAddr; - - return false; - } - - return true; -} - -Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex( - uint32_t &bp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - - lldb::addr_t break_addr; - - for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { - break_addr = m_hbr_regs[bp_index].address; - - if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { - m_hbr_regs[bp_index].hit_addr = trap_addr; - return Status(); - } - } - - bp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm::%s()", __FUNCTION__); - - Status error; - - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return error; - - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if (m_hbr_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hbr_regs[i].address; - tempControl = m_hbr_regs[i].control; - - // Clear breakpoints in local cache - m_hbr_regs[i].control &= ~1; - m_hbr_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeBREAK, i); - - if (error.Fail()) { - m_hbr_regs[i].control = tempControl; - m_hbr_regs[i].address = tempAddr; - - return error; - } - } - } - - return Status(); -} - -uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - LLDB_LOG(log, "{0}", m_max_hwp_supported); - return m_max_hwp_supported; -} - -uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, - watch_flags); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0; - lldb::addr_t real_addr = addr; - - // Check if we are setting watchpoint other than read/write/access Also - // update watchpoint flag to match Arm write-read bit configuration. - switch (watch_flags) { - case 1: - watch_flags = 2; - break; - case 2: - watch_flags = 1; - break; - case 3: - break; - default: - return LLDB_INVALID_INDEX32; - } - - // Can't watch zero bytes - // Can't watch more than 4 bytes per WVR/WCR pair - - if (size == 0 || size > 4) - return LLDB_INVALID_INDEX32; - - // Check 4-byte alignment for hardware watchpoint target address. Below is a - // hack to recalculate address and size in order to make sure we can watch - // non 4-byte alligned addresses as well. - if (addr & 0x03) { - uint8_t watch_mask = (addr & 0x03) + size; - - if (watch_mask > 0x04) - return LLDB_INVALID_INDEX32; - else if (watch_mask <= 0x02) - size = 2; - else if (watch_mask <= 0x04) - size = 4; - - addr = addr & (~0x03); - } - - // We can only watch up to four bytes that follow a 4 byte aligned address - // per watchpoint register pair, so make sure we can properly encode this. - addr_word_offset = addr % 4; - byte_mask = ((1u << size) - 1u) << addr_word_offset; - - // Check if we need multiple watchpoint register - if (byte_mask > 0xfu) - return LLDB_INVALID_INDEX32; - - // Setup control value - // Make the byte_mask into a valid Byte Address Select mask - control_value = byte_mask << 5; - - // Turn on appropriate watchpoint flags read or write - control_value |= (watch_flags << 3); - - // Enable this watchpoint and make it stop in privileged or user mode; - control_value |= 7; - - // Make sure bits 1:0 are clear in our address - addr &= ~((lldb::addr_t)3); - - // Iterate over stored watchpoints and find a free wp_index - wp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if ((m_hwp_regs[i].control & 1) == 0) { - wp_index = i; // Mark last free slot - } else if (m_hwp_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. - } - } - - if (wp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].real_addr = real_addr; - m_hwp_regs[wp_index].address = addr; - m_hwp_regs[wp_index].control = control_value; - - // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); - - if (error.Fail()) { - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].control &= ~1; - - return LLDB_INVALID_INDEX32; - } - - return wp_index; -} - -bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( - uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return false; - - if (wp_index >= m_max_hwp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; - uint32_t tempControl = m_hwp_regs[wp_index].control; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].control &= ~1; - m_hwp_regs[wp_index].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); - - if (error.Fail()) { - m_hwp_regs[wp_index].control = tempControl; - m_hwp_regs[wp_index].address = tempAddr; - - return false; - } - - return true; -} - -Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return error; - - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if (m_hwp_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hwp_regs[i].address; - tempControl = m_hwp_regs[i].control; - - // Clear watchpoints in local cache - m_hwp_regs[i].control &= ~1; - m_hwp_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); - - if (error.Fail()) { - m_hwp_regs[i].control = tempControl; - m_hwp_regs[i].address = tempAddr; - - return error; - } - } - } - - return Status(); -} - -uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) { - case 0x01: - return 1; - case 0x03: - return 2; - case 0x07: - return 3; - case 0x0f: - return 4; - default: - return 0; - } -} -bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) - return true; - else - return false; -} - -Status -NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); - - uint32_t watch_size; - lldb::addr_t watch_addr; - - for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { - watch_size = GetWatchpointSize(wp_index); - watch_addr = m_hwp_regs[wp_index].address; - - if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && - trap_addr < watch_addr + watch_size) { - m_hwp_regs[wp_index].hit_addr = trap_addr; - return Status(); - } - } - - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -lldb::addr_t -NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].real_addr; - else - return LLDB_INVALID_ADDRESS; -} - -lldb::addr_t -NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].hit_addr; - else - return LLDB_INVALID_ADDRESS; -} - -Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { - Status error; - - if (!m_refresh_hwdebug_info) { - return Status(); - } - - unsigned int cap_val; - - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), - nullptr, &cap_val, - sizeof(unsigned int)); - - if (error.Fail()) - return error; - - m_max_hwp_supported = (cap_val >> 8) & 0xff; - m_max_hbp_supported = cap_val & 0xff; - m_refresh_hwdebug_info = false; - - return error; -} - -Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, - int hwb_index) { - Status error; - - lldb::addr_t *addr_buf; - uint32_t *ctrl_buf; - - if (hwbType == eDREGTypeWATCH) { - addr_buf = &m_hwp_regs[hwb_index].address; - ctrl_buf = &m_hwp_regs[hwb_index].control; - - error = NativeProcessLinux::PtraceWrapper( - PTRACE_SETHBPREGS, m_thread.GetID(), - (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf, - sizeof(unsigned int)); - - if (error.Fail()) - return error; - - error = NativeProcessLinux::PtraceWrapper( - PTRACE_SETHBPREGS, m_thread.GetID(), - (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf, - sizeof(unsigned int)); - } else { - addr_buf = &m_hbr_regs[hwb_index].address; - ctrl_buf = &m_hbr_regs[hwb_index].control; - - error = NativeProcessLinux::PtraceWrapper( - PTRACE_SETHBPREGS, m_thread.GetID(), - (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf, - sizeof(unsigned int)); - - if (error.Fail()) - return error; - - error = NativeProcessLinux::PtraceWrapper( - PTRACE_SETHBPREGS, m_thread.GetID(), - (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf, - sizeof(unsigned int)); - } - - return error; -} - -uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; -} - -Status NativeRegisterContextLinux_arm::DoReadRegisterValue( - uint32_t offset, const char *reg_name, uint32_t size, - RegisterValue &value) { - // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android - // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we - // read out the full GPR register set instead. This approach is about 4 times - // slower but the performance overhead is negligible in comparision to - // processing time in lldb-server. - assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); - if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) - return Status("Register isn't fit into the size of the GPR area"); - - Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); - if (error.Fail()) - return error; - - value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]); - return Status(); -} - -Status NativeRegisterContextLinux_arm::DoWriteRegisterValue( - uint32_t offset, const char *reg_name, const RegisterValue &value) { - // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android - // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we - // read out the full GPR register set, modify the requested register and - // write it back. This approach is about 4 times slower but the performance - // overhead is negligible in comparision to processing time in lldb-server. - assert(offset % 4 == 0 && "Try to write a register with unaligned offset"); - if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm)) - return Status("Register isn't fit into the size of the GPR area"); - - Status error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm)); - if (error.Fail()) - return error; - - uint32_t reg_value = value.GetAsUInt32(); - // As precaution for an undefined behavior encountered while setting PC we - // will clear thumb bit of new PC if we are already in thumb mode; that is - // CPSR thumb mode bit is set. - if (offset / sizeof(uint32_t) == gpr_pc_arm) { - // Check if we are already in thumb mode and thumb bit of current PC is - // read out to be zero and thumb bit of next PC is read out to be one. - if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) && - (value.GetAsUInt32() & 0x01)) { - reg_value &= (~1ull); - } - } - - m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; - return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); -} - -Status NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size) { -#ifdef __arm__ - return NativeRegisterContextLinux::DoReadGPR(buf, buf_size); -#else // __aarch64__ - struct iovec ioVec; - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - - return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS); -#endif // __arm__ -} - -Status NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size) { -#ifdef __arm__ - return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size); -#else // __aarch64__ - struct iovec ioVec; - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - - return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS); -#endif // __arm__ -} - -Status NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size) { -#ifdef __arm__ - return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(), - nullptr, buf, buf_size); -#else // __aarch64__ - struct iovec ioVec; - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - - return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP); -#endif // __arm__ -} - -Status NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size) { -#ifdef __arm__ - return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(), - nullptr, buf, buf_size); -#else // __aarch64__ - struct iovec ioVec; - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - - return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP); -#endif // __arm__ -} - -#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h deleted file mode 100644 index d0b068550a9ee..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ /dev/null @@ -1,169 +0,0 @@ -//===-- NativeRegisterContextLinux_arm.h ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - -#ifndef lldb_NativeRegisterContextLinux_arm_h -#define lldb_NativeRegisterContextLinux_arm_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/lldb-arm-register-enums.h" - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_arm(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - uint32_t GetUserRegisterCount() const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - //------------------------------------------------------------------ - // Hardware breakpoints/watchpoint management functions - //------------------------------------------------------------------ - - uint32_t NumSupportedHardwareBreakpoints() override; - - uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - bool ClearHardwareBreakpoint(uint32_t hw_idx) override; - - Status ClearAllHardwareBreakpoints() override; - - Status GetHardwareBreakHitIndex(uint32_t &bp_index, - lldb::addr_t trap_addr) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - bool ClearHardwareWatchpoint(uint32_t hw_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t GetWatchpointSize(uint32_t wp_index); - - bool WatchpointIsEnabled(uint32_t wp_index); - - // Debug register type select - enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; - -protected: - Status DoReadRegisterValue(uint32_t offset, const char *reg_name, - uint32_t size, RegisterValue &value) override; - - Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, - const RegisterValue &value) override; - - Status DoReadGPR(void *buf, size_t buf_size) override; - - Status DoWriteGPR(void *buf, size_t buf_size) override; - - Status DoReadFPR(void *buf, size_t buf_size) override; - - Status DoWriteFPR(void *buf, size_t buf_size) override; - - void *GetGPRBuffer() override { return &m_gpr_arm; } - - void *GetFPRBuffer() override { return &m_fpr; } - - size_t GetFPRSize() override { return sizeof(m_fpr); } - -private: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - struct QReg { - uint8_t bytes[16]; - }; - - struct FPU { - union { - uint32_t s[32]; - uint64_t d[32]; - QReg q[16]; // the 128-bit NEON registers - } floats; - uint32_t fpscr; - }; - - uint32_t m_gpr_arm[k_num_gpr_registers_arm]; - RegInfo m_reg_info; - FPU m_fpr; - - // Debug register info for hardware breakpoints and watchpoints management. - struct DREG { - lldb::addr_t address; // Breakpoint/watchpoint address value. - lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception - // occurred. - lldb::addr_t real_addr; // Address value that should cause target to stop. - uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and reference counter. - }; - - struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints - struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints - - uint32_t m_max_hwp_supported; - uint32_t m_max_hbp_supported; - bool m_refresh_hwdebug_info; - - bool IsGPR(unsigned reg) const; - - bool IsFPR(unsigned reg) const; - - Status ReadHardwareDebugInfo(); - - Status WriteHardwareDebugRegs(int hwbType, int hwb_index); - - uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h - -#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp deleted file mode 100644 index 9a392edbe9ef3..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ /dev/null @@ -1,985 +0,0 @@ -//===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__arm64__) || defined(__aarch64__) - -#include "NativeRegisterContextLinux_arm.h" -#include "NativeRegisterContextLinux_arm64.h" - - -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" - -// System includes - They have to be included after framework includes because -// they define some macros which collide with variable names in other modules -#include <sys/socket.h> -// NT_PRSTATUS and NT_FPREGSET definition -#include <elf.h> -// user_hwdebug_state definition -#include <asm/ptrace.h> - -#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -// ARM64 general purpose registers. -static const uint32_t g_gpr_regnums_arm64[] = { - gpr_x0_arm64, gpr_x1_arm64, gpr_x2_arm64, gpr_x3_arm64, - gpr_x4_arm64, gpr_x5_arm64, gpr_x6_arm64, gpr_x7_arm64, - gpr_x8_arm64, gpr_x9_arm64, gpr_x10_arm64, gpr_x11_arm64, - gpr_x12_arm64, gpr_x13_arm64, gpr_x14_arm64, gpr_x15_arm64, - gpr_x16_arm64, gpr_x17_arm64, gpr_x18_arm64, gpr_x19_arm64, - gpr_x20_arm64, gpr_x21_arm64, gpr_x22_arm64, gpr_x23_arm64, - gpr_x24_arm64, gpr_x25_arm64, gpr_x26_arm64, gpr_x27_arm64, - gpr_x28_arm64, gpr_fp_arm64, gpr_lr_arm64, gpr_sp_arm64, - gpr_pc_arm64, gpr_cpsr_arm64, gpr_w0_arm64, gpr_w1_arm64, - gpr_w2_arm64, gpr_w3_arm64, gpr_w4_arm64, gpr_w5_arm64, - gpr_w6_arm64, gpr_w7_arm64, gpr_w8_arm64, gpr_w9_arm64, - gpr_w10_arm64, gpr_w11_arm64, gpr_w12_arm64, gpr_w13_arm64, - gpr_w14_arm64, gpr_w15_arm64, gpr_w16_arm64, gpr_w17_arm64, - gpr_w18_arm64, gpr_w19_arm64, gpr_w20_arm64, gpr_w21_arm64, - gpr_w22_arm64, gpr_w23_arm64, gpr_w24_arm64, gpr_w25_arm64, - gpr_w26_arm64, gpr_w27_arm64, gpr_w28_arm64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - - 1) == k_num_gpr_registers_arm64, - "g_gpr_regnums_arm64 has wrong number of register infos"); - -// ARM64 floating point registers. -static const uint32_t g_fpu_regnums_arm64[] = { - fpu_v0_arm64, fpu_v1_arm64, fpu_v2_arm64, fpu_v3_arm64, - fpu_v4_arm64, fpu_v5_arm64, fpu_v6_arm64, fpu_v7_arm64, - fpu_v8_arm64, fpu_v9_arm64, fpu_v10_arm64, fpu_v11_arm64, - fpu_v12_arm64, fpu_v13_arm64, fpu_v14_arm64, fpu_v15_arm64, - fpu_v16_arm64, fpu_v17_arm64, fpu_v18_arm64, fpu_v19_arm64, - fpu_v20_arm64, fpu_v21_arm64, fpu_v22_arm64, fpu_v23_arm64, - fpu_v24_arm64, fpu_v25_arm64, fpu_v26_arm64, fpu_v27_arm64, - fpu_v28_arm64, fpu_v29_arm64, fpu_v30_arm64, fpu_v31_arm64, - fpu_s0_arm64, fpu_s1_arm64, fpu_s2_arm64, fpu_s3_arm64, - fpu_s4_arm64, fpu_s5_arm64, fpu_s6_arm64, fpu_s7_arm64, - fpu_s8_arm64, fpu_s9_arm64, fpu_s10_arm64, fpu_s11_arm64, - fpu_s12_arm64, fpu_s13_arm64, fpu_s14_arm64, fpu_s15_arm64, - fpu_s16_arm64, fpu_s17_arm64, fpu_s18_arm64, fpu_s19_arm64, - fpu_s20_arm64, fpu_s21_arm64, fpu_s22_arm64, fpu_s23_arm64, - fpu_s24_arm64, fpu_s25_arm64, fpu_s26_arm64, fpu_s27_arm64, - fpu_s28_arm64, fpu_s29_arm64, fpu_s30_arm64, fpu_s31_arm64, - - fpu_d0_arm64, fpu_d1_arm64, fpu_d2_arm64, fpu_d3_arm64, - fpu_d4_arm64, fpu_d5_arm64, fpu_d6_arm64, fpu_d7_arm64, - fpu_d8_arm64, fpu_d9_arm64, fpu_d10_arm64, fpu_d11_arm64, - fpu_d12_arm64, fpu_d13_arm64, fpu_d14_arm64, fpu_d15_arm64, - fpu_d16_arm64, fpu_d17_arm64, fpu_d18_arm64, fpu_d19_arm64, - fpu_d20_arm64, fpu_d21_arm64, fpu_d22_arm64, fpu_d23_arm64, - fpu_d24_arm64, fpu_d25_arm64, fpu_d26_arm64, fpu_d27_arm64, - fpu_d28_arm64, fpu_d29_arm64, fpu_d30_arm64, fpu_d31_arm64, - fpu_fpsr_arm64, fpu_fpcr_arm64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - - 1) == k_num_fpr_registers_arm64, - "g_fpu_regnums_arm64 has wrong number of register infos"); - -namespace { -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; -} - -// Register sets for ARM64. -static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm64, - g_gpr_regnums_arm64}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, - g_fpu_regnums_arm64}}; - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - switch (target_arch.GetMachine()) { - case llvm::Triple::arm: - return llvm::make_unique<NativeRegisterContextLinux_arm>(target_arch, - native_thread); - case llvm::Triple::aarch64: - return llvm::make_unique<NativeRegisterContextLinux_arm64>(target_arch, - native_thread); - default: - llvm_unreachable("have no register context for architecture"); - } -} - -NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_arm64(target_arch)) { - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - m_reg_info.num_registers = k_num_registers_arm64; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; - m_reg_info.last_gpr = k_last_gpr_arm64; - m_reg_info.first_fpr = k_first_fpr_arm64; - m_reg_info.last_fpr = k_last_fpr_arm64; - m_reg_info.first_fpr_v = fpu_v0_arm64; - m_reg_info.last_fpr_v = fpu_v31_arm64; - m_reg_info.gpr_flags = gpr_cpsr_arm64; - break; - default: - llvm_unreachable("Unhandled target architecture."); - break; - } - - ::memset(&m_fpr, 0, sizeof(m_fpr)); - ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64)); - ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); - ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); - - // 16 is just a maximum value, query hardware for actual watchpoint count - m_max_hwp_supported = 16; - m_max_hbp_supported = 16; - m_refresh_hwdebug_info = true; -} - -uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { - return k_num_register_sets; -} - -const RegisterSet * -NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const { - if (set_index < k_num_register_sets) - return &g_reg_sets_arm64[set_index]; - - return nullptr; -} - -uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) - count += g_reg_sets_arm64[set_index].num_registers; - return count; -} - -Status -NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsFPR(reg)) { - error = ReadFPR(); - if (error.Fail()) - return error; - } 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]; - } - - error = ReadRegisterRaw(full_reg, reg_value); - - if (error.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)) - reg_value.SetUInt64(reg_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 (reg_value.GetByteSize() > reg_info->byte_size) - reg_value.SetType(reg_info); - } - return error; - } - - // Get pointer to m_fpr variable and set the data from it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < sizeof m_fpr); - uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; - reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, - eByteOrderLittle, error); - - return error; -} - -Status NativeRegisterContextLinux_arm64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - if (IsGPR(reg_index)) - return WriteRegisterRaw(reg_index, reg_value); - - if (IsFPR(reg_index)) { - // Get pointer to m_fpr variable and set the data to it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < sizeof m_fpr); - uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; - switch (reg_info->byte_size) { - case 2: - *(uint16_t *)dst = reg_value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled register data size %" PRIu32, - reg_info->byte_size); - } - - Status error = WriteFPR(); - if (error.Fail()) - return error; - - return Status(); - } - - return Status("failed - register wasn't recognized to be a GPR or an FPR, " - "write strategy unknown"); -} - -Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) - return Status("failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - - error = ReadGPR(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - - ::memcpy(dst, &m_gpr_arm64, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, &m_fpr, sizeof(m_fpr)); - - return error; -} - -Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - ::memcpy(&m_gpr_arm64, src, GetRegisterInfoInterface().GetGPRSize()); - - error = WriteGPR(); - if (error.Fail()) - return error; - - src += GetRegisterInfoInterface().GetGPRSize(); - ::memcpy(&m_fpr, src, sizeof(m_fpr)); - - error = WriteFPR(); - if (error.Fail()) - return error; - - return error; -} - -bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const { - return reg <= m_reg_info.last_gpr; // GPR's come first. -} - -bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); -} - -uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - - Status error; - - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - return m_max_hbp_supported; -} - -uint32_t -NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, bp_index = 0; - - // Check if size has a valid hardware breakpoint length. - if (size != 4) - return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware - // breakpoint - - // Check 4-byte alignment for hardware breakpoint target address. - if (addr & 0x03) - return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. - - // Setup control value - control_value = 0; - control_value |= ((1 << size) - 1) << 5; - control_value |= (2 << 1) | 1; - - // Iterate over stored breakpoints and find a free bp_index - bp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if ((m_hbr_regs[i].control & 1) == 0) { - bp_index = i; // Mark last free slot - } else if (m_hbr_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. - } - } - - if (bp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update breakpoint in local cache - m_hbr_regs[bp_index].real_addr = addr; - m_hbr_regs[bp_index].address = addr; - m_hbr_regs[bp_index].control = control_value; - - // PTRACE call to set corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK); - - if (error.Fail()) { - m_hbr_regs[bp_index].address = 0; - m_hbr_regs[bp_index].control &= ~1; - - return LLDB_INVALID_INDEX32; - } - - return bp_index; -} - -bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint( - uint32_t hw_idx) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "hw_idx: {0}", hw_idx); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return false; - - if (hw_idx >= m_max_hbp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; - uint32_t tempControl = m_hbr_regs[hw_idx].control; - - m_hbr_regs[hw_idx].control &= ~1; - m_hbr_regs[hw_idx].address = 0; - - // PTRACE call to clear corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK); - - if (error.Fail()) { - m_hbr_regs[hw_idx].control = tempControl; - m_hbr_regs[hw_idx].address = tempAddr; - - return false; - } - - return true; -} - -Status NativeRegisterContextLinux_arm64::GetHardwareBreakHitIndex( - uint32_t &bp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - - lldb::addr_t break_addr; - - for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { - break_addr = m_hbr_regs[bp_index].address; - - if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { - m_hbr_regs[bp_index].hit_addr = trap_addr; - return Status(); - } - } - - bp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_arm64::ClearAllHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - if (log) - log->Printf("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - - Status error; - - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return error; - - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if (m_hbr_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hbr_regs[i].address; - tempControl = m_hbr_regs[i].control; - - // Clear watchpoints in local cache - m_hbr_regs[i].control &= ~1; - m_hbr_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeBREAK); - - if (error.Fail()) { - m_hbr_regs[i].control = tempControl; - m_hbr_regs[i].address = tempAddr; - - return error; - } - } - } - - return Status(); -} - -uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - LLDB_LOG(log, "{0}", m_max_hwp_supported); - return m_max_hwp_supported; -} - -uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, - watch_flags); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, wp_index = 0; - lldb::addr_t real_addr = addr; - - // Check if we are setting watchpoint other than read/write/access Also - // update watchpoint flag to match AArch64 write-read bit configuration. - switch (watch_flags) { - case 1: - watch_flags = 2; - break; - case 2: - watch_flags = 1; - break; - case 3: - break; - default: - return LLDB_INVALID_INDEX32; - } - - // Check if size has a valid hardware watchpoint length. - if (size != 1 && size != 2 && size != 4 && size != 8) - return LLDB_INVALID_INDEX32; - - // Check 8-byte alignment for hardware watchpoint target address. Below is a - // hack to recalculate address and size in order to make sure we can watch - // non 8-byte alligned addresses as well. - if (addr & 0x07) { - uint8_t watch_mask = (addr & 0x07) + size; - - if (watch_mask > 0x08) - return LLDB_INVALID_INDEX32; - else if (watch_mask <= 0x02) - size = 2; - else if (watch_mask <= 0x04) - size = 4; - else - size = 8; - - addr = addr & (~0x07); - } - - // Setup control value - control_value = watch_flags << 3; - control_value |= ((1 << size) - 1) << 5; - control_value |= (2 << 1) | 1; - - // Iterate over stored watchpoints and find a free wp_index - wp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if ((m_hwp_regs[i].control & 1) == 0) { - wp_index = i; // Mark last free slot - } else if (m_hwp_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. - } - } - - if (wp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].real_addr = real_addr; - m_hwp_regs[wp_index].address = addr; - m_hwp_regs[wp_index].control = control_value; - - // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH); - - if (error.Fail()) { - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].control &= ~1; - - return LLDB_INVALID_INDEX32; - } - - return wp_index; -} - -bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint( - uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return false; - - if (wp_index >= m_max_hwp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; - uint32_t tempControl = m_hwp_regs[wp_index].control; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].control &= ~1; - m_hwp_regs[wp_index].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH); - - if (error.Fail()) { - m_hwp_regs[wp_index].control = tempControl; - m_hwp_regs[wp_index].address = tempAddr; - - return false; - } - - return true; -} - -Status NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return error; - - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if (m_hwp_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hwp_regs[i].address; - tempControl = m_hwp_regs[i].control; - - // Clear watchpoints in local cache - m_hwp_regs[i].control &= ~1; - m_hwp_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH); - - if (error.Fail()) { - m_hwp_regs[i].control = tempControl; - m_hwp_regs[i].address = tempAddr; - - return error; - } - } - } - - return Status(); -} - -uint32_t -NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { - case 0x01: - return 1; - case 0x03: - return 2; - case 0x0f: - return 4; - case 0xff: - return 8; - default: - return 0; - } -} -bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) - return true; - else - return false; -} - -Status NativeRegisterContextLinux_arm64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); - - uint32_t watch_size; - lldb::addr_t watch_addr; - - for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { - watch_size = GetWatchpointSize(wp_index); - watch_addr = m_hwp_regs[wp_index].address; - - if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && - trap_addr < watch_addr + watch_size) { - m_hwp_regs[wp_index].hit_addr = trap_addr; - return Status(); - } - } - - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -lldb::addr_t -NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].real_addr; - else - return LLDB_INVALID_ADDRESS; -} - -lldb::addr_t -NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].hit_addr; - else - return LLDB_INVALID_ADDRESS; -} - -Status NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { - if (!m_refresh_hwdebug_info) { - return Status(); - } - - ::pid_t tid = m_thread.GetID(); - - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Status error; - - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof(dreg_state); - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - - if (error.Fail()) - return error; - - m_max_hwp_supported = dreg_state.dbg_info & 0xff; - - regset = NT_ARM_HW_BREAK; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - - if (error.Fail()) - return error; - - m_max_hbp_supported = dreg_state.dbg_info & 0xff; - m_refresh_hwdebug_info = false; - - return error; -} - -Status NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Status error; - - memset(&dreg_state, 0, sizeof(dreg_state)); - ioVec.iov_base = &dreg_state; - - if (hwbType == eDREGTypeWATCH) { - hwbType = NT_ARM_HW_WATCH; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; - } - } else { - hwbType = NT_ARM_HW_BREAK; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; - } - } - - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - &hwbType, &ioVec, ioVec.iov_len); -} - -Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( - uint32_t offset, const char *reg_name, uint32_t size, - RegisterValue &value) { - Status error; - if (offset > sizeof(struct user_pt_regs)) { - offset -= sizeof(struct user_pt_regs); - if (offset > sizeof(struct user_fpsimd_state)) { - error.SetErrorString("invalid offset value"); - return error; - } - elf_fpregset_t regs; - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); - if (error.Success()) { - value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, - m_thread.GetProcess().GetByteOrder()); - } - } else { - elf_gregset_t regs; - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); - if (error.Success()) { - value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, - m_thread.GetProcess().GetByteOrder()); - } - } - return error; -} - -Status NativeRegisterContextLinux_arm64::DoWriteRegisterValue( - uint32_t offset, const char *reg_name, const RegisterValue &value) { - Status error; - ::pid_t tid = m_thread.GetID(); - if (offset > sizeof(struct user_pt_regs)) { - offset -= sizeof(struct user_pt_regs); - if (offset > sizeof(struct user_fpsimd_state)) { - error.SetErrorString("invalid offset value"); - return error; - } - elf_fpregset_t regs; - int regset = NT_FPREGSET; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, sizeof regs); - - if (error.Success()) { - ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), - 16); - error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, - &ioVec, sizeof regs); - } - } else { - elf_gregset_t regs; - int regset = NT_PRSTATUS; - struct iovec ioVec; - - ioVec.iov_base = ®s; - ioVec.iov_len = sizeof regs; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, sizeof regs); - if (error.Success()) { - ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), - 8); - error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, - &ioVec, sizeof regs); - } - } - return error; -} - -Status NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) { - int regset = NT_PRSTATUS; - struct iovec ioVec; - Status error; - - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), - ®set, &ioVec, buf_size); -} - -Status NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, - size_t buf_size) { - int regset = NT_PRSTATUS; - struct iovec ioVec; - Status error; - - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - ®set, &ioVec, buf_size); -} - -Status NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) { - int regset = NT_FPREGSET; - struct iovec ioVec; - Status error; - - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), - ®set, &ioVec, buf_size); -} - -Status NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, - size_t buf_size) { - int regset = NT_FPREGSET; - struct iovec ioVec; - Status error; - - ioVec.iov_base = buf; - ioVec.iov_len = buf_size; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - ®set, &ioVec, buf_size); -} - -uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; -} - -#endif // defined (__arm64__) || defined (__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h deleted file mode 100644 index c859d4249d053..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ /dev/null @@ -1,169 +0,0 @@ -//===-- NativeRegisterContextLinux_arm64.h ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__arm64__) || defined(__aarch64__) - -#ifndef lldb_NativeRegisterContextLinux_arm64_h -#define lldb_NativeRegisterContextLinux_arm64_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/lldb-arm64-register-enums.h" - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_arm64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - uint32_t GetUserRegisterCount() const override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - //------------------------------------------------------------------ - // Hardware breakpoints/watchpoint management functions - //------------------------------------------------------------------ - - uint32_t NumSupportedHardwareBreakpoints() override; - - uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - bool ClearHardwareBreakpoint(uint32_t hw_idx) override; - - Status ClearAllHardwareBreakpoints() override; - - Status GetHardwareBreakHitIndex(uint32_t &bp_index, - lldb::addr_t trap_addr) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - bool ClearHardwareWatchpoint(uint32_t hw_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t GetWatchpointSize(uint32_t wp_index); - - bool WatchpointIsEnabled(uint32_t wp_index); - - // Debug register type select - enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; - -protected: - Status DoReadRegisterValue(uint32_t offset, const char *reg_name, - uint32_t size, RegisterValue &value) override; - - Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, - const RegisterValue &value) override; - - Status DoReadGPR(void *buf, size_t buf_size) override; - - Status DoWriteGPR(void *buf, size_t buf_size) override; - - Status DoReadFPR(void *buf, size_t buf_size) override; - - Status DoWriteFPR(void *buf, size_t buf_size) override; - - void *GetGPRBuffer() override { return &m_gpr_arm64; } - - void *GetFPRBuffer() override { return &m_fpr; } - - size_t GetFPRSize() override { return sizeof(m_fpr); } - -private: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - // based on RegisterContextDarwin_arm64.h - struct VReg { - uint8_t bytes[16]; - }; - - // based on RegisterContextDarwin_arm64.h - struct FPU { - VReg v[32]; - uint32_t fpsr; - uint32_t fpcr; - }; - - uint64_t m_gpr_arm64[k_num_gpr_registers_arm64]; // 64-bit general purpose - // registers. - RegInfo m_reg_info; - FPU m_fpr; // floating-point registers including extended register sets. - - // Debug register info for hardware breakpoints and watchpoints management. - struct DREG { - lldb::addr_t address; // Breakpoint/watchpoint address value. - lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception - // occurred. - lldb::addr_t real_addr; // Address value that should cause target to stop. - uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and reference counter. - }; - - struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints - struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints - - uint32_t m_max_hwp_supported; - uint32_t m_max_hbp_supported; - bool m_refresh_hwdebug_info; - - bool IsGPR(unsigned reg) const; - - bool IsFPR(unsigned reg) const; - - Status ReadHardwareDebugInfo(); - - Status WriteHardwareDebugRegs(int hwbType); - - uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_arm64_h - -#endif // defined (__arm64__) || defined (__aarch64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp deleted file mode 100644 index d641056a04401..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -//===-- NativeRegisterContextLinux_mips64.cpp ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__mips__) - -#include "NativeRegisterContextLinux_mips64.h" - - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" -#include "lldb/Core/EmulateInstruction.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-private-enumerations.h" -#define NT_MIPS_MSA 0x600 -#define CONFIG5_FRE (1 << 8) -#define SR_FR (1 << 26) -#define NUM_REGISTERS 32 - -#include <asm/ptrace.h> -#include <sys/ptrace.h> - -#ifndef PTRACE_GET_WATCH_REGS -enum pt_watch_style { pt_watch_style_mips32, pt_watch_style_mips64 }; -struct mips32_watch_regs { - uint32_t watchlo[8]; - uint16_t watchhi[8]; - uint16_t watch_masks[8]; - uint32_t num_valid; -} __attribute__((aligned(8))); - -struct mips64_watch_regs { - uint64_t watchlo[8]; - uint16_t watchhi[8]; - uint16_t watch_masks[8]; - uint32_t num_valid; -} __attribute__((aligned(8))); - -struct pt_watch_regs { - enum pt_watch_style style; - union { - struct mips32_watch_regs mips32; - struct mips64_watch_regs mips64; - }; -}; - -#define PTRACE_GET_WATCH_REGS 0xd0 -#define PTRACE_SET_WATCH_REGS 0xd1 -#endif - -#define W (1 << 0) -#define R (1 << 1) -#define I (1 << 2) - -#define IRW (I | R | W) - -#ifndef PTRACE_GETREGSET -#define PTRACE_GETREGSET 0x4204 -#endif -struct pt_watch_regs default_watch_regs; - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return llvm::make_unique<NativeRegisterContextLinux_mips64>(target_arch, - native_thread); -} - -#define REG_CONTEXT_SIZE \ - (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR_linux_mips) + \ - sizeof(MSA_linux_mips)) - -// ---------------------------------------------------------------------------- -// NativeRegisterContextLinux_mips64 members. -// ---------------------------------------------------------------------------- - -static RegisterInfoInterface * -CreateRegisterInfoInterface(const ArchSpec &target_arch) { - if ((target_arch.GetMachine() == llvm::Triple::mips) || - (target_arch.GetMachine() == llvm::Triple::mipsel)) { - // 32-bit hosts run with a RegisterContextLinux_mips context. - return new RegisterContextLinux_mips( - target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); - } else { - return new RegisterContextLinux_mips64( - target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); - } -} - -NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)) { - switch (target_arch.GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - m_reg_info.num_registers = k_num_registers_mips; - m_reg_info.num_gpr_registers = k_num_gpr_registers_mips; - m_reg_info.num_fpr_registers = k_num_fpr_registers_mips; - m_reg_info.last_gpr = k_last_gpr_mips; - m_reg_info.first_fpr = k_first_fpr_mips; - m_reg_info.last_fpr = k_last_fpr_mips; - m_reg_info.first_msa = k_first_msa_mips; - m_reg_info.last_msa = k_last_msa_mips; - break; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - m_reg_info.num_registers = k_num_registers_mips64; - m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64; - m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64; - m_reg_info.last_gpr = k_last_gpr_mips64; - m_reg_info.first_fpr = k_first_fpr_mips64; - m_reg_info.last_fpr = k_last_fpr_mips64; - m_reg_info.first_msa = k_first_msa_mips64; - m_reg_info.last_msa = k_last_msa_mips64; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - // Initialize m_iovec to point to the buffer and buffer size using the - // conventions of Berkeley style UIO structures, as required by PTRACE - // extensions. - m_iovec.iov_base = &m_msa; - m_iovec.iov_len = sizeof(MSA_linux_mips); - - // init h/w watchpoint addr map - for (int index = 0; index <= MAX_NUM_WP; index++) - hw_addr_map[index] = LLDB_INVALID_ADDRESS; - - ::memset(&m_gpr, 0, sizeof(GPR_linux_mips)); - ::memset(&m_fpr, 0, sizeof(FPR_linux_mips)); - ::memset(&m_msa, 0, sizeof(MSA_linux_mips)); -} - -uint32_t NativeRegisterContextLinux_mips64::GetRegisterSetCount() const { - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - const auto context = static_cast<const RegisterContextLinux_mips64 &> - (GetRegisterInfoInterface()); - return context.GetRegisterSetCount(); - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: { - const auto context = static_cast<const RegisterContextLinux_mips &> - (GetRegisterInfoInterface()); - return context.GetRegisterSetCount(); - } - default: - llvm_unreachable("Unhandled target architecture."); - } -} - -lldb::addr_t NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation( - lldb::addr_t fail_value) { - Status error; - RegisterValue pc_value; - lldb::addr_t pc = fail_value; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "Reading PC from breakpoint location"); - - // PC register is at index 34 of the register array - const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex(gpr_pc_mips64); - - error = ReadRegister(pc_info_p, pc_value); - if (error.Success()) { - pc = pc_value.GetAsUInt64(); - - // CAUSE register is at index 37 of the register array - const RegisterInfo *const cause_info_p = - GetRegisterInfoAtIndex(gpr_cause_mips64); - RegisterValue cause_value; - - ReadRegister(cause_info_p, cause_value); - - uint64_t cause = cause_value.GetAsUInt64(); - LLDB_LOG(log, "PC {0:x} cause {1:x}", pc, cause); - - /* - * The breakpoint might be in a delay slot. In this case PC points - * to the delayed branch instruction rather then the instruction - * in the delay slot. If the CAUSE.BD flag is set then adjust the - * PC based on the size of the branch instruction. - */ - if ((cause & (1 << 31)) != 0) { - lldb::addr_t branch_delay = 0; - branch_delay = - 4; // FIXME - Adjust according to size of branch instruction at PC - pc = pc + branch_delay; - pc_value.SetUInt64(pc); - WriteRegister(pc_info_p, pc_value); - LLDB_LOG(log, "New PC {0:x}", pc); - } - } - - return pc; -} - -const RegisterSet * -NativeRegisterContextLinux_mips64::GetRegisterSet(uint32_t set_index) const { - if (set_index >= GetRegisterSetCount()) - return nullptr; - - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - const auto context = static_cast<const RegisterContextLinux_mips64 &> - (GetRegisterInfoInterface()); - return context.GetRegisterSet(set_index); - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: { - const auto context = static_cast<const RegisterContextLinux_mips &> - (GetRegisterInfoInterface()); - return context.GetRegisterSet(set_index); - } - default: - llvm_unreachable("Unhandled target architecture."); - } -} - -lldb_private::Status -NativeRegisterContextLinux_mips64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - uint8_t byte_size = reg_info->byte_size; - if (reg == LLDB_INVALID_REGNUM) { - // This is likely an internal register for lldb use only and should not be - // directly queried. - error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " - "register, cannot read directly", - reg_info->name); - return error; - } - - if (IsMSA(reg) && !IsMSAAvailable()) { - error.SetErrorString("MSA not available on this processor"); - return error; - } - - if (IsMSA(reg) || IsFPR(reg)) { - uint8_t *src = nullptr; - lldbassert(reg_info->byte_offset < sizeof(UserArea)); - - error = ReadCP1(); - - if (!error.Success()) { - error.SetErrorString("failed to read co-processor 1 register"); - return error; - } - - if (IsFPR(reg)) { - if (IsFR0() && (byte_size != 4)) { - byte_size = 4; - uint8_t ptrace_index; - ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - src = ReturnFPOffset(ptrace_index, reg_info->byte_offset); - } else - src = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); - } else - src = (uint8_t *)&m_msa + reg_info->byte_offset - - (sizeof(m_gpr) + sizeof(m_fpr)); - switch (byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - case 16: - reg_value.SetBytes((const void *)src, 16, GetByteOrder()); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - } else { - error = ReadRegisterRaw(reg, reg_value); - } - - return error; -} - -lldb_private::Status NativeRegisterContextLinux_mips64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - Status error; - - assert(reg_info && "reg_info is null"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - if (IsMSA(reg_index) && !IsMSAAvailable()) { - error.SetErrorString("MSA not available on this processor"); - return error; - } - - if (IsFPR(reg_index) || IsMSA(reg_index)) { - uint8_t *dst = nullptr; - uint64_t *src = nullptr; - uint8_t byte_size = reg_info->byte_size; - lldbassert(reg_info->byte_offset < sizeof(UserArea)); - - // Initialise the FP and MSA buffers by reading all co-processor 1 - // registers - ReadCP1(); - - if (IsFPR(reg_index)) { - if (IsFR0() && (byte_size != 4)) { - byte_size = 4; - uint8_t ptrace_index; - ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - dst = ReturnFPOffset(ptrace_index, reg_info->byte_offset); - } else - dst = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); - } else - dst = (uint8_t *)&m_msa + reg_info->byte_offset - - (sizeof(m_gpr) + sizeof(m_fpr)); - switch (byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - case 16: - src = (uint64_t *)reg_value.GetBytes(); - *(uint64_t *)dst = *src; - *(uint64_t *)(dst + 8) = *(src + 1); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - error = WriteCP1(); - if (!error.Success()) { - error.SetErrorString("failed to write co-processor 1 register"); - return error; - } - } else { - error = WriteRegisterRaw(reg_index, reg_value); - } - - return error; -} - -Status NativeRegisterContextLinux_mips64::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) { - error.SetErrorStringWithFormat( - "failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - return error; - } - - error = ReadGPR(); - if (!error.Success()) { - error.SetErrorString("ReadGPR() failed"); - return error; - } - - error = ReadCP1(); - if (!error.Success()) { - error.SetErrorString("ReadCP1() failed"); - return error; - } - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - - ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); - dst += GetRegisterInfoInterface().GetGPRSize(); - - ::memcpy(dst, &m_fpr, GetFPRSize()); - dst += GetFPRSize(); - - ::memcpy(dst, &m_msa, sizeof(MSA_linux_mips)); - - return error; -} - -Status NativeRegisterContextLinux_mips64::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_mips64::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - - ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); - src += GetRegisterInfoInterface().GetGPRSize(); - - ::memcpy(&m_fpr, src, GetFPRSize()); - src += GetFPRSize(); - - ::memcpy(&m_msa, src, sizeof(MSA_linux_mips)); - - error = WriteGPR(); - if (!error.Success()) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s WriteGPR() failed", - __FUNCTION__); - return error; - } - - error = WriteCP1(); - if (!error.Success()) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s WriteCP1() failed", - __FUNCTION__); - return error; - } - - return error; -} - -Status NativeRegisterContextLinux_mips64::ReadCP1() { - Status error; - - uint8_t *src = nullptr; - uint8_t *dst = nullptr; - - lldb::ByteOrder byte_order = GetByteOrder(); - - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - - if (IsMSAAvailable()) { - error = NativeRegisterContextLinux::ReadRegisterSet( - &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); - src = (uint8_t *)&m_msa + (IsBigEndian * 8); - dst = (uint8_t *)&m_fpr; - for (int i = 0; i < NUM_REGISTERS; i++) { - // Copy fp values from msa buffer fetched via ptrace - *(uint64_t *)dst = *(uint64_t *)src; - src = src + 16; - dst = dst + 8; - } - m_fpr.fir = m_msa.fir; - m_fpr.fcsr = m_msa.fcsr; - m_fpr.config5 = m_msa.config5; - } else { - error = NativeRegisterContextLinux::ReadFPR(); - } - return error; -} - -uint8_t * -NativeRegisterContextLinux_mips64::ReturnFPOffset(uint8_t reg_index, - uint32_t byte_offset) { - - uint8_t *fp_buffer_ptr = nullptr; - lldb::ByteOrder byte_order = GetByteOrder(); - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - if (reg_index % 2) { - uint8_t offset_diff = (IsBigEndian) ? 8 : 4; - fp_buffer_ptr = - (uint8_t *)&m_fpr + byte_offset - offset_diff - sizeof(m_gpr); - } else { - fp_buffer_ptr = - (uint8_t *)&m_fpr + byte_offset + 4 * (IsBigEndian) - sizeof(m_gpr); - } - return fp_buffer_ptr; -} - -Status NativeRegisterContextLinux_mips64::WriteCP1() { - Status error; - - uint8_t *src = nullptr; - uint8_t *dst = nullptr; - - lldb::ByteOrder byte_order = GetByteOrder(); - - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - - if (IsMSAAvailable()) { - dst = (uint8_t *)&m_msa + (IsBigEndian * 8); - src = (uint8_t *)&m_fpr; - for (int i = 0; i < NUM_REGISTERS; i++) { - // Copy fp values to msa buffer for ptrace - *(uint64_t *)dst = *(uint64_t *)src; - dst = dst + 16; - src = src + 8; - } - m_msa.fir = m_fpr.fir; - m_msa.fcsr = m_fpr.fcsr; - m_msa.config5 = m_fpr.config5; - error = NativeRegisterContextLinux::WriteRegisterSet( - &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); - } else { - error = NativeRegisterContextLinux::WriteFPR(); - } - - return error; -} - -bool NativeRegisterContextLinux_mips64::IsFR0() { - const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex(gpr_sr_mips64); - - RegisterValue reg_value; - ReadRegister(reg_info_p, reg_value); - - uint64_t value = reg_value.GetAsUInt64(); - - return (!(value & SR_FR)); -} - -bool NativeRegisterContextLinux_mips64::IsFRE() { - const RegisterInfo *const reg_info_p = - GetRegisterInfoAtIndex(gpr_config5_mips64); - - RegisterValue reg_value; - ReadRegister(reg_info_p, reg_value); - - uint64_t config5 = reg_value.GetAsUInt64(); - - return (config5 & CONFIG5_FRE); -} - -bool NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const { - return (m_reg_info.first_fpr <= reg_index && - reg_index <= m_reg_info.last_fpr); -} - -static uint32_t GetWatchHi(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watchhi[index]; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watchhi[index]; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static void SetWatchHi(struct pt_watch_regs *regs, uint32_t index, - uint16_t value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - regs->mips32.watchhi[index] = value; - else if (regs->style == pt_watch_style_mips64) - regs->mips64.watchhi[index] = value; - LLDB_LOG(log, "Invalid watch register style"); - return; -} - -static lldb::addr_t GetWatchLo(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watchlo[index]; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watchlo[index]; - LLDB_LOG(log, "Invalid watch register style"); - return LLDB_INVALID_ADDRESS; -} - -static void SetWatchLo(struct pt_watch_regs *regs, uint32_t index, - uint64_t value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - regs->mips32.watchlo[index] = (uint32_t)value; - else if (regs->style == pt_watch_style_mips64) - regs->mips64.watchlo[index] = value; - else - LLDB_LOG(log, "Invalid watch register style"); -} - -static uint32_t GetIRWMask(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watch_masks[index] & IRW; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watch_masks[index] & IRW; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static uint32_t GetRegMask(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watch_masks[index] & ~IRW; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watch_masks[index] & ~IRW; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static lldb::addr_t GetRangeMask(lldb::addr_t mask) { - lldb::addr_t mask_bit = 1; - while (mask_bit < mask) { - mask = mask | mask_bit; - mask_bit <<= 1; - } - return mask; -} - -static int GetVacantWatchIndex(struct pt_watch_regs *regs, lldb::addr_t addr, - uint32_t size, uint32_t irw, - uint32_t num_valid) { - lldb::addr_t last_byte = addr + size - 1; - lldb::addr_t mask = GetRangeMask(addr ^ last_byte) | IRW; - lldb::addr_t base_addr = addr & ~mask; - - // Check if this address is already watched by previous watch points. - lldb::addr_t lo; - uint16_t hi; - uint32_t vacant_watches = 0; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(regs, index); - if (lo != 0 && irw == ((uint32_t)lo & irw)) { - hi = GetWatchHi(regs, index) | IRW; - lo &= ~(lldb::addr_t)hi; - if (addr >= lo && last_byte <= (lo + hi)) - return index; - } else - vacant_watches++; - } - - // Now try to find a vacant index - if (vacant_watches > 0) { - vacant_watches = 0; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(regs, index); - if (lo == 0 && irw == (GetIRWMask(regs, index) & irw)) { - if (mask <= (GetRegMask(regs, index) | IRW)) { - // It fits, we can use it. - SetWatchLo(regs, index, base_addr | irw); - SetWatchHi(regs, index, mask & ~IRW); - return index; - } else { - // It doesn't fit, but has the proper IRW capabilities - vacant_watches++; - } - } - } - - if (vacant_watches > 1) { - // Split this watchpoint accross several registers - struct pt_watch_regs regs_copy; - regs_copy = *regs; - lldb::addr_t break_addr; - uint32_t segment_size; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(®s_copy, index); - hi = GetRegMask(®s_copy, index) | IRW; - if (lo == 0 && irw == (hi & irw)) { - lo = addr & ~(lldb::addr_t)hi; - break_addr = lo + hi + 1; - if (break_addr >= addr + size) - segment_size = size; - else - segment_size = break_addr - addr; - mask = GetRangeMask(addr ^ (addr + segment_size - 1)); - SetWatchLo(®s_copy, index, (addr & ~mask) | irw); - SetWatchHi(®s_copy, index, mask & ~IRW); - if (break_addr >= addr + size) { - *regs = regs_copy; - return index; - } - size = addr + size - break_addr; - addr = break_addr; - } - } - } - } - return LLDB_INVALID_INDEX32; -} - -bool NativeRegisterContextLinux_mips64::IsMSA(uint32_t reg_index) const { - return (m_reg_info.first_msa <= reg_index && - reg_index <= m_reg_info.last_msa); -} - -bool NativeRegisterContextLinux_mips64::IsMSAAvailable() { - MSA_linux_mips msa_buf; - unsigned int regset = NT_MIPS_MSA; - - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGSET, Host::GetCurrentProcessID(), - static_cast<void *>(®set), &msa_buf, sizeof(MSA_linux_mips)); - - if (error.Success() && msa_buf.mir) { - return true; - } - - return false; -} - -Status NativeRegisterContextLinux_mips64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // reading the current state of watch regs - struct pt_watch_regs watch_readback; - Status error = DoReadWatchPointRegisterValue( - m_thread.GetID(), static_cast<void *>(&watch_readback)); - - if (GetWatchHi(&watch_readback, wp_index) & (IRW)) { - // clear hit flag in watchhi - SetWatchHi(&watch_readback, wp_index, - (GetWatchHi(&watch_readback, wp_index) & ~(IRW))); - DoWriteWatchPointRegisterValue(m_thread.GetID(), - static_cast<void *>(&watch_readback)); - - is_hit = true; - return error; - } - is_hit = false; - return error; -} - -Status NativeRegisterContextLinux_mips64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_mips64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - is_vacant = false; - return Status("MIPS TODO: " - "NativeRegisterContextLinux_mips64::IsWatchpointVacant not " - "implemented"); -} - -bool NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - struct pt_watch_regs regs; - // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - if (regs.style == pt_watch_style_mips32) { - regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index]; - regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index]; - regs.mips32.watch_masks[wp_index] = - default_watch_regs.mips32.watch_masks[wp_index]; - } else // pt_watch_style_mips64 - { - regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index]; - regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index]; - regs.mips64.watch_masks[wp_index] = - default_watch_regs.mips64.watch_masks[wp_index]; - } - - Status error = DoWriteWatchPointRegisterValue(m_thread.GetID(), - static_cast<void *>(®s)); - if (!error.Fail()) { - hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS; - return true; - } - return false; -} - -Status NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() { - return DoWriteWatchPointRegisterValue( - m_thread.GetID(), static_cast<void *>(&default_watch_regs)); -} - -Status NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - Status error; - error.SetErrorString("MIPS TODO: " - "NativeRegisterContextLinux_mips64::" - "SetHardwareWatchpointWithIndex not implemented"); - return error; -} - -uint32_t NativeRegisterContextLinux_mips64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - struct pt_watch_regs regs; - - // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - // Try if a new watch point fits in this state - int index = GetVacantWatchIndex(®s, addr, size, watch_flags, - NumSupportedHardwareWatchpoints()); - - // New watchpoint doesn't fit - if (index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // It fits, so we go ahead with updating the state of watch regs - DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - // Storing exact address - hw_addr_map[index] = addr; - return index; -} - -lldb::addr_t -NativeRegisterContextLinux_mips64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - - return hw_addr_map[wp_index]; -} - -struct EmulatorBaton { - lldb::addr_t m_watch_hit_addr; - NativeProcessLinux *m_process; - NativeRegisterContext *m_reg_context; - - EmulatorBaton(NativeProcessLinux *process, NativeRegisterContext *reg_context) - : m_watch_hit_addr(LLDB_INVALID_ADDRESS), m_process(process), - m_reg_context(reg_context) {} -}; - -static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, void *dst, size_t length) { - size_t bytes_read; - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); - return bytes_read; -} - -static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, const void *dst, - size_t length) { - return length; -} - -static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, - const RegisterInfo *reg_info, - RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - const RegisterInfo *full_reg_info = - emulator_baton->m_reg_context->GetRegisterInfo( - lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]); - - Status error = - emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); - if (error.Success()) - return true; - - return false; -} - -static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - const RegisterInfo *reg_info, - const RegisterValue ®_value) { - if (reg_info->kinds[lldb::eRegisterKindDWARF] == dwarf_bad_mips64) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64(); - } - - return true; -} - -/* - * MIPS Linux kernel returns a masked address (last 3bits are masked) - * when a HW watchpoint is hit. However user may not have set a watchpoint - * on this address. Emulate instruction at PC and find the base address of - * the load/store instruction. This will give the exact address used to - * read/write the variable. Send this exact address to client so that - * it can decide to stop or continue the thread. -*/ -lldb::addr_t -NativeRegisterContextLinux_mips64::GetWatchpointHitAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - - lldb_private::ArchSpec arch; - arch = GetRegisterInfoInterface().GetTargetArchitecture(); - std::unique_ptr<EmulateInstruction> emulator_ap( - EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny, - nullptr)); - - if (emulator_ap == nullptr) - return LLDB_INVALID_ADDRESS; - - EmulatorBaton baton( - static_cast<NativeProcessLinux *>(&m_thread.GetProcess()), this); - emulator_ap->SetBaton(&baton); - emulator_ap->SetReadMemCallback(&ReadMemoryCallback); - emulator_ap->SetReadRegCallback(&ReadRegisterCallback); - emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); - emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); - - if (!emulator_ap->ReadInstruction()) - return LLDB_INVALID_ADDRESS; - - if (emulator_ap->EvaluateInstruction(lldb::eEmulateInstructionOptionNone)) - return baton.m_watch_hit_addr; - - return LLDB_INVALID_ADDRESS; -} - -uint32_t NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - struct pt_watch_regs regs; - static int num_valid = 0; - if (!num_valid) { - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - default_watch_regs = - regs; // Keeping default watch regs values for future use - switch (regs.style) { - case pt_watch_style_mips32: - num_valid = regs.mips32.num_valid; // Using num_valid as cache - return num_valid; - case pt_watch_style_mips64: - num_valid = regs.mips64.num_valid; - return num_valid; - } - LLDB_LOG(log, "Invalid watch register style"); - return 0; - } - return num_valid; -} - -Status -NativeRegisterContextLinux_mips64::ReadRegisterRaw(uint32_t reg_index, - RegisterValue &value) { - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - - if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); - - uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - - if ((offset == ptrace_sr_mips) || (offset == ptrace_config5_mips)) - return Read_SR_Config(reg_info->byte_offset, reg_info->name, - reg_info->byte_size, value); - - return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size, - value); -} - -Status NativeRegisterContextLinux_mips64::WriteRegisterRaw( - uint32_t reg_index, const RegisterValue &value) { - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - - if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); - - if (reg_info->invalidate_regs) - lldbassert(false && "reg_info->invalidate_regs is unhandled"); - - uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - return DoWriteRegisterValue(offset, reg_info->name, value); -} - -Status NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset, - const char *reg_name, - uint32_t size, - RegisterValue &value) { - GPR_linux_mips regs; - ::memset(®s, 0, sizeof(GPR_linux_mips)); - - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); - if (error.Success()) { - const lldb_private::ArchSpec &arch = - m_thread.GetProcess().GetArchitecture(); - void *target_address = ((uint8_t *)®s) + offset + - 4 * (arch.GetMachine() == llvm::Triple::mips); - value.SetUInt(*(uint32_t *)target_address, size); - } - return error; -} - -Status NativeRegisterContextLinux_mips64::DoReadWatchPointRegisterValue( - lldb::tid_t tid, void *watch_readback) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GET_WATCH_REGS, - m_thread.GetID(), watch_readback); -} - -Status NativeRegisterContextLinux_mips64::DoWriteWatchPointRegisterValue( - lldb::tid_t tid, void *watch_reg_value) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS, - m_thread.GetID(), watch_reg_value); -} - -#endif // defined (__mips__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h deleted file mode 100644 index c4e984a545bc6..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ /dev/null @@ -1,140 +0,0 @@ -//===-- NativeRegisterContextLinux_mips64.h ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__mips__) - -#ifndef lldb_NativeRegisterContextLinux_mips64_h -#define lldb_NativeRegisterContextLinux_mips64_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/RegisterContext_mips.h" -#include "Plugins/Process/Utility/lldb-mips-linux-register-enums.h" -#include <sys/uio.h> - -#define MAX_NUM_WP 8 - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_mips64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - lldb::addr_t GetPCfromBreakpointLocation( - lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override; - - lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - Status ReadCP1(); - - Status WriteCP1(); - - uint8_t *ReturnFPOffset(uint8_t reg_index, uint32_t byte_offset); - - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - static bool IsMSAAvailable(); - -protected: - Status Read_SR_Config(uint32_t offset, const char *reg_name, uint32_t size, - RegisterValue &value); - - Status ReadRegisterRaw(uint32_t reg_index, RegisterValue &value) override; - - Status WriteRegisterRaw(uint32_t reg_index, - const RegisterValue &value) override; - - Status DoReadWatchPointRegisterValue(lldb::tid_t tid, void *watch_readback); - - Status DoWriteWatchPointRegisterValue(lldb::tid_t tid, void *watch_readback); - - bool IsFR0(); - - bool IsFRE(); - - bool IsFPR(uint32_t reg_index) const; - - bool IsMSA(uint32_t reg_index) const; - - void *GetGPRBuffer() override { return &m_gpr; } - - void *GetFPRBuffer() override { return &m_fpr; } - - size_t GetFPRSize() override { return sizeof(FPR_linux_mips); } - -private: - // Info about register ranges. - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - uint32_t first_msa; - uint32_t last_msa; - }; - - RegInfo m_reg_info; - - GPR_linux_mips m_gpr; - - FPR_linux_mips m_fpr; - - MSA_linux_mips m_msa; - - lldb::addr_t hw_addr_map[MAX_NUM_WP]; - - struct iovec m_iovec; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_mips64_h - -#endif // defined (__mips__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp deleted file mode 100644 index da51fda1c80b3..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp +++ /dev/null @@ -1,804 +0,0 @@ -//===-- NativeRegisterContextLinux_ppc64le.cpp ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// This implementation is related to the OpenPOWER ABI for Power Architecture -// 64-bit ELF V2 ABI - -#if defined(__powerpc64__) - -#include "NativeRegisterContextLinux_ppc64le.h" - -#include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" - -// System includes - They have to be included after framework includes because -// they define some macros which collide with variable names in other modules -#include <sys/socket.h> -#include <elf.h> -#include <asm/ptrace.h> - -#define REG_CONTEXT_SIZE \ - (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le)) -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -static const uint32_t g_gpr_regnums_ppc64le[] = { - gpr_r0_ppc64le, gpr_r1_ppc64le, gpr_r2_ppc64le, gpr_r3_ppc64le, - gpr_r4_ppc64le, gpr_r5_ppc64le, gpr_r6_ppc64le, gpr_r7_ppc64le, - gpr_r8_ppc64le, gpr_r9_ppc64le, gpr_r10_ppc64le, gpr_r11_ppc64le, - gpr_r12_ppc64le, gpr_r13_ppc64le, gpr_r14_ppc64le, gpr_r15_ppc64le, - gpr_r16_ppc64le, gpr_r17_ppc64le, gpr_r18_ppc64le, gpr_r19_ppc64le, - gpr_r20_ppc64le, gpr_r21_ppc64le, gpr_r22_ppc64le, gpr_r23_ppc64le, - gpr_r24_ppc64le, gpr_r25_ppc64le, gpr_r26_ppc64le, gpr_r27_ppc64le, - gpr_r28_ppc64le, gpr_r29_ppc64le, gpr_r30_ppc64le, gpr_r31_ppc64le, - gpr_pc_ppc64le, gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le, - gpr_lr_ppc64le, gpr_xer_ppc64le, gpr_cr_ppc64le, gpr_softe_ppc64le, - gpr_trap_ppc64le, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; - -static const uint32_t g_fpr_regnums_ppc64le[] = { - fpr_f0_ppc64le, fpr_f1_ppc64le, fpr_f2_ppc64le, fpr_f3_ppc64le, - fpr_f4_ppc64le, fpr_f5_ppc64le, fpr_f6_ppc64le, fpr_f7_ppc64le, - fpr_f8_ppc64le, fpr_f9_ppc64le, fpr_f10_ppc64le, fpr_f11_ppc64le, - fpr_f12_ppc64le, fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le, - fpr_f16_ppc64le, fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le, - fpr_f20_ppc64le, fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le, - fpr_f24_ppc64le, fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le, - fpr_f28_ppc64le, fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le, - fpr_fpscr_ppc64le, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; - -static const uint32_t g_vmx_regnums_ppc64le[] = { - vmx_vr0_ppc64le, vmx_vr1_ppc64le, vmx_vr2_ppc64le, vmx_vr3_ppc64le, - vmx_vr4_ppc64le, vmx_vr5_ppc64le, vmx_vr6_ppc64le, vmx_vr7_ppc64le, - vmx_vr8_ppc64le, vmx_vr9_ppc64le, vmx_vr10_ppc64le, vmx_vr11_ppc64le, - vmx_vr12_ppc64le, vmx_vr13_ppc64le, vmx_vr14_ppc64le, vmx_vr15_ppc64le, - vmx_vr16_ppc64le, vmx_vr17_ppc64le, vmx_vr18_ppc64le, vmx_vr19_ppc64le, - vmx_vr20_ppc64le, vmx_vr21_ppc64le, vmx_vr22_ppc64le, vmx_vr23_ppc64le, - vmx_vr24_ppc64le, vmx_vr25_ppc64le, vmx_vr26_ppc64le, vmx_vr27_ppc64le, - vmx_vr28_ppc64le, vmx_vr29_ppc64le, vmx_vr30_ppc64le, vmx_vr31_ppc64le, - vmx_vscr_ppc64le, vmx_vrsave_ppc64le, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; - -static const uint32_t g_vsx_regnums_ppc64le[] = { - vsx_vs0_ppc64le, vsx_vs1_ppc64le, vsx_vs2_ppc64le, vsx_vs3_ppc64le, - vsx_vs4_ppc64le, vsx_vs5_ppc64le, vsx_vs6_ppc64le, vsx_vs7_ppc64le, - vsx_vs8_ppc64le, vsx_vs9_ppc64le, vsx_vs10_ppc64le, vsx_vs11_ppc64le, - vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le, - vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le, - vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le, - vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le, - vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le, - vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le, - vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le, - vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le, - vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le, - vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le, - vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le, - vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le, - vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; - -namespace { -// Number of register sets provided by this context. -enum { k_num_register_sets = 4 }; -} - -static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le, - g_gpr_regnums_ppc64le}, - {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le, - g_fpr_regnums_ppc64le}, - {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le, - g_vmx_regnums_ppc64le}, - {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le, - g_vsx_regnums_ppc64le}, -}; - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - switch (target_arch.GetMachine()) { - case llvm::Triple::ppc64le: - return llvm::make_unique<NativeRegisterContextLinux_ppc64le>(target_arch, - native_thread); - default: - llvm_unreachable("have no register context for architecture"); - } -} - -NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_ppc64le(target_arch)) { - if (target_arch.GetMachine() != llvm::Triple::ppc64le) { - llvm_unreachable("Unhandled target architecture."); - } - - ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); - ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); - ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); - ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); - ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); -} - -uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const { - return k_num_register_sets; -} - -const RegisterSet * -NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const { - if (set_index < k_num_register_sets) - return &g_reg_sets_ppc64le[set_index]; - - return nullptr; -} - -uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) - count += g_reg_sets_ppc64le[set_index].num_registers; - return count; -} - -Status NativeRegisterContextLinux_ppc64le::ReadRegister( - const RegisterInfo *reg_info, RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (IsFPR(reg)) { - error = ReadFPR(); - if (error.Fail()) - return error; - - // Get pointer to m_fpr_ppc64le variable and set the data from it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < sizeof m_fpr_ppc64le); - uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; - reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, - eByteOrderLittle, error); - } else if (IsVSX(reg)) { - uint32_t vsx_offset = CalculateVsxOffset(reg_info); - assert(vsx_offset < sizeof(m_vsx_ppc64le)); - - if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { - error = ReadVSX(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - uint64_t value[2]; - uint8_t *dst, *src; - dst = (uint8_t *)&value; - src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; - ::memcpy(dst, src, 8); - dst += 8; - src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; - ::memcpy(dst, src, 8); - reg_value.SetFromMemoryData(reg_info, &value, reg_info->byte_size, - eByteOrderLittle, error); - } else { - error = ReadVMX(); - if (error.Fail()) - return error; - - // Get pointer to m_vmx_ppc64le variable and set the data from it. - uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; - uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; - reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, - eByteOrderLittle, error); - } - } else if (IsVMX(reg)) { - error = ReadVMX(); - if (error.Fail()) - return error; - - // Get pointer to m_vmx_ppc64le variable and set the data from it. - uint32_t vmx_offset = CalculateVmxOffset(reg_info); - assert(vmx_offset < sizeof m_vmx_ppc64le); - uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; - reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, - eByteOrderLittle, error); - } else if (IsGPR(reg)) { - error = ReadGPR(); - if (error.Fail()) - return error; - - uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; - reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, - eByteOrderLittle, error); - } else { - return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " - "or VMX, read strategy unknown"); - } - - return error; -} - -Status NativeRegisterContextLinux_ppc64le::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - Status error; - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - if (IsGPR(reg_index)) { - error = ReadGPR(); - if (error.Fail()) - return error; - - uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; - ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); - - error = WriteGPR(); - if (error.Fail()) - return error; - - return Status(); - } - - if (IsFPR(reg_index)) { - error = ReadFPR(); - if (error.Fail()) - return error; - - // Get pointer to m_fpr_ppc64le variable and set the data to it. - uint32_t fpr_offset = CalculateFprOffset(reg_info); - assert(fpr_offset < GetFPRSize()); - uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; - ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); - - error = WriteFPR(); - if (error.Fail()) - return error; - - return Status(); - } - - if (IsVMX(reg_index)) { - error = ReadVMX(); - if (error.Fail()) - return error; - - // Get pointer to m_vmx_ppc64le variable and set the data to it. - uint32_t vmx_offset = CalculateVmxOffset(reg_info); - assert(vmx_offset < sizeof(m_vmx_ppc64le)); - uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; - ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); - - error = WriteVMX(); - if (error.Fail()) - return error; - - return Status(); - } - - if (IsVSX(reg_index)) { - uint32_t vsx_offset = CalculateVsxOffset(reg_info); - assert(vsx_offset < sizeof(m_vsx_ppc64le)); - - if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { - error = ReadVSX(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - uint64_t value[2]; - ::memcpy(value, reg_value.GetBytes(), 16); - uint8_t *dst, *src; - src = (uint8_t *)value; - dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; - ::memcpy(dst, src, 8); - src += 8; - dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; - ::memcpy(dst, src, 8); - - WriteVSX(); - WriteFPR(); - } else { - error = ReadVMX(); - if (error.Fail()) - return error; - - // Get pointer to m_vmx_ppc64le variable and set the data from it. - uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; - uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; - ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); - WriteVMX(); - } - - return Status(); - } - - return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " - "or VMX, write strategy unknown"); -} - -Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) - return Status("failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - - error = ReadGPR(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - error = ReadVMX(); - if (error.Fail()) - return error; - - error = ReadVSX(); - if (error.Fail()) - return error; - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - - ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); - dst += GetFPRSize(); - ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); - dst += sizeof(m_vmx_ppc64le); - ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); - - return error; -} - -Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - - ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); - error = WriteGPR(); - - if (error.Fail()) - return error; - - src += GetGPRSize(); - ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); - - error = WriteFPR(); - if (error.Fail()) - return error; - - src += GetFPRSize(); - ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); - - error = WriteVMX(); - if (error.Fail()) - return error; - - src += sizeof(m_vmx_ppc64le); - ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); - error = WriteVSX(); - - return error; -} - -bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const { - return reg <= k_last_gpr_ppc64le; // GPR's come first. -} - -bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const { - return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); -} - -Status NativeRegisterContextLinux_ppc64le::DoReadGPR( - void *buf, size_t buf_size) { - int regset = NT_PRSTATUS; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), - ®set, buf, buf_size); -} - -Status NativeRegisterContextLinux_ppc64le::DoWriteGPR( - void *buf, size_t buf_size) { - int regset = NT_PRSTATUS; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), - ®set, buf, buf_size); -} - -Status NativeRegisterContextLinux_ppc64le::DoReadFPR(void *buf, - size_t buf_size) { - int regset = NT_FPREGSET; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), - ®set, buf, buf_size); -} - -Status NativeRegisterContextLinux_ppc64le::DoWriteFPR(void *buf, - size_t buf_size) { - int regset = NT_FPREGSET; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), - ®set, buf, buf_size); -} - -uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; -} - -uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; -} - -uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; -} - -Status NativeRegisterContextLinux_ppc64le::ReadVMX() { - int regset = NT_PPC_VMX; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), - ®set, &m_vmx_ppc64le, - sizeof(m_vmx_ppc64le)); -} - -Status NativeRegisterContextLinux_ppc64le::WriteVMX() { - int regset = NT_PPC_VMX; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(), - ®set, &m_vmx_ppc64le, - sizeof(m_vmx_ppc64le)); -} - -Status NativeRegisterContextLinux_ppc64le::ReadVSX() { - int regset = NT_PPC_VSX; - return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), - ®set, &m_vsx_ppc64le, - sizeof(m_vsx_ppc64le)); -} - -Status NativeRegisterContextLinux_ppc64le::WriteVSX() { - int regset = NT_PPC_VSX; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(), - ®set, &m_vsx_ppc64le, - sizeof(m_vsx_ppc64le)); -} - -bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) { - return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); -} - -bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) { - return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); -} - -uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - LLDB_LOG(log, "{0}", m_max_hwp_supported); - return m_max_hwp_supported; -} - -uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, - watch_flags); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, wp_index = 0; - lldb::addr_t real_addr = addr; - uint32_t rw_mode = 0; - - // Check if we are setting watchpoint other than read/write/access Update - // watchpoint flag to match ppc64le write-read bit configuration. - switch (watch_flags) { - case eWatchpointKindWrite: - rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE; - watch_flags = 2; - break; - case eWatchpointKindRead: - rw_mode = PPC_BREAKPOINT_TRIGGER_READ; - watch_flags = 1; - break; - case (eWatchpointKindRead | eWatchpointKindWrite): - rw_mode = PPC_BREAKPOINT_TRIGGER_RW; - break; - default: - return LLDB_INVALID_INDEX32; - } - - // Check if size has a valid hardware watchpoint length. - if (size != 1 && size != 2 && size != 4 && size != 8) - return LLDB_INVALID_INDEX32; - - // Check 8-byte alignment for hardware watchpoint target address. Below is a - // hack to recalculate address and size in order to make sure we can watch - // non 8-byte alligned addresses as well. - if (addr & 0x07) { - - addr_t begin = llvm::alignDown(addr, 8); - addr_t end = llvm::alignTo(addr + size, 8); - size = llvm::PowerOf2Ceil(end - begin); - - addr = addr & (~0x07); - } - - // Setup control value - control_value = watch_flags << 3; - control_value |= ((1 << size) - 1) << 5; - control_value |= (2 << 1) | 1; - - // Iterate over stored watchpoints and find a free wp_index - wp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if ((m_hwp_regs[i].control & 1) == 0) { - wp_index = i; // Mark last free slot - } else if (m_hwp_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. - } - } - - if (wp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update watchpoint in local cache - m_hwp_regs[wp_index].real_addr = real_addr; - m_hwp_regs[wp_index].address = addr; - m_hwp_regs[wp_index].control = control_value; - m_hwp_regs[wp_index].mode = rw_mode; - - // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(); - - if (error.Fail()) { - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1); - - return LLDB_INVALID_INDEX32; - } - - return wp_index; -} - -bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint( - uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return false; - - if (wp_index >= m_max_hwp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; - uint32_t tempControl = m_hwp_regs[wp_index].control; - long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot); - - // Update watchpoint in local cache - m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1); - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].slot = 0; - m_hwp_regs[wp_index].mode = 0; - - // Ptrace call to update hardware debug registers - error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG, - m_thread.GetID(), 0, tempSlot); - - if (error.Fail()) { - m_hwp_regs[wp_index].control = tempControl; - m_hwp_regs[wp_index].address = tempAddr; - m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot); - - return false; - } - - return true; -} - -uint32_t -NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; - if (llvm::isPowerOf2_32(control + 1)) { - return llvm::countPopulation(control); - } - - return 0; -} - -bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled( - uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); -} - -Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); - - uint32_t watch_size; - lldb::addr_t watch_addr; - - for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { - watch_size = GetWatchpointSize(wp_index); - watch_addr = m_hwp_regs[wp_index].address; - - if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && - trap_addr <= watch_addr + watch_size) { - m_hwp_regs[wp_index].hit_addr = trap_addr; - return Status(); - } - } - - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -lldb::addr_t -NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].real_addr; - else - return LLDB_INVALID_ADDRESS; -} - -lldb::addr_t -NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; - - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].hit_addr; - - return LLDB_INVALID_ADDRESS; -} - -Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() { - if (!m_refresh_hwdebug_info) { - return Status(); - } - - ::pid_t tid = m_thread.GetID(); - - struct ppc_debug_info hwdebug_info; - Status error; - - error = NativeProcessLinux::PtraceWrapper( - PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info)); - - if (error.Fail()) - return error; - - m_max_hwp_supported = hwdebug_info.num_data_bps; - m_max_hbp_supported = hwdebug_info.num_instruction_bps; - m_refresh_hwdebug_info = false; - - return error; -} - -Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() { - struct ppc_hw_breakpoint reg_state; - Status error; - long ret; - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - reg_state.addr = m_hwp_regs[i].address; - reg_state.trigger_type = m_hwp_regs[i].mode; - reg_state.version = 1; - reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT; - reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; - reg_state.addr2 = 0; - reg_state.condition_value = 0; - - error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG, - m_thread.GetID(), 0, ®_state, - sizeof(reg_state), &ret); - - if (error.Fail()) - return error; - - m_hwp_regs[i].slot = ret; - } - - return error; -} - -#endif // defined(__powerpc64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h deleted file mode 100644 index 2c4471962ad0d..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h +++ /dev/null @@ -1,149 +0,0 @@ -//===-- NativeRegisterContextLinux_ppc64le.h --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// This implementation is related to the OpenPOWER ABI for Power Architecture -// 64-bit ELF V2 ABI - -#if defined(__powerpc64__) - -#ifndef lldb_NativeRegisterContextLinux_ppc64le_h -#define lldb_NativeRegisterContextLinux_ppc64le_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" - -#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT -#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" -#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_ppc64le(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - uint32_t GetUserRegisterCount() const override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - //------------------------------------------------------------------ - // Hardware watchpoint management functions - //------------------------------------------------------------------ - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - bool ClearHardwareWatchpoint(uint32_t hw_index) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t GetWatchpointSize(uint32_t wp_index); - - bool WatchpointIsEnabled(uint32_t wp_index); - -protected: - Status DoReadGPR(void *buf, size_t buf_size) override; - - Status DoWriteGPR(void *buf, size_t buf_size) override; - - Status DoReadFPR(void *buf, size_t buf_size) override; - - Status DoWriteFPR(void *buf, size_t buf_size) override; - - bool IsVMX(unsigned reg); - - bool IsVSX(unsigned reg); - - Status ReadVMX(); - - Status WriteVMX(); - - Status ReadVSX(); - - Status WriteVSX(); - - void *GetGPRBuffer() override { return &m_gpr_ppc64le; } - - void *GetFPRBuffer() override { return &m_fpr_ppc64le; } - - size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); } - -private: - GPR m_gpr_ppc64le; // 64-bit general purpose registers. - FPR m_fpr_ppc64le; // floating-point registers including extended register. - VMX m_vmx_ppc64le; // VMX registers. - VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers. - - bool IsGPR(unsigned reg) const; - - bool IsFPR(unsigned reg) const; - - bool IsVMX(unsigned reg) const; - - bool IsVSX(unsigned reg) const; - - uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; - - uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const; - - uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const; - - Status ReadHardwareDebugInfo(); - - Status WriteHardwareDebugRegs(); - - // Debug register info for hardware watchpoints management. - struct DREG { - lldb::addr_t address; // Breakpoint/watchpoint address value. - lldb::addr_t hit_addr; // Address at which last watchpoint trigger - // exception occurred. - lldb::addr_t real_addr; // Address value that should cause target to stop. - uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and reference counter. - long slot; // Saves the value returned from PTRACE_SETHWDEBUG. - int mode; // Defines if watchpoint is read/write/access. - }; - - std::array<DREG, 4> m_hwp_regs; - - // 16 is just a maximum value, query hardware for actual watchpoint count - uint32_t m_max_hwp_supported = 16; - uint32_t m_max_hbp_supported = 16; - bool m_refresh_hwdebug_info = true; -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_ppc64le_h - -#endif // defined(__powerpc64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp deleted file mode 100644 index 1bc916b69bcd1..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ /dev/null @@ -1,638 +0,0 @@ -//===-- NativeRegisterContextLinux_s390x.cpp --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__s390x__) && defined(__linux__) - -#include "NativeRegisterContextLinux_s390x.h" -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" - -#include <asm/ptrace.h> -#include <linux/uio.h> -#include <sys/ptrace.h> - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -// ---------------------------------------------------------------------------- -// Private namespace. -// ---------------------------------------------------------------------------- - -namespace { -// s390x 64-bit general purpose registers. -static const uint32_t g_gpr_regnums_s390x[] = { - lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x, - lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x, - lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x, - lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x, - lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x, - lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x, - lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x, - lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x, - lldb_pswm_s390x, lldb_pswa_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - - 1 == - k_num_gpr_registers_s390x, - "g_gpr_regnums_s390x has wrong number of register infos"); - -// s390x 64-bit floating point registers. -static const uint32_t g_fpu_regnums_s390x[] = { - lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x, - lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x, - lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x, - lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x, - lldb_fpc_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - - 1 == - k_num_fpr_registers_s390x, - "g_fpu_regnums_s390x has wrong number of register infos"); - -// s390x Linux operating-system information. -static const uint32_t g_linux_regnums_s390x[] = { - lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_linux_regnums_s390x) / - sizeof(g_linux_regnums_s390x[0])) - - 1 == - k_num_linux_registers_s390x, - "g_linux_regnums_s390x has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_register_sets = 3 }; - -// Register sets for s390x 64-bit. -static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x, - g_gpr_regnums_s390x}, - {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x, - g_fpu_regnums_s390x}, - {"Linux Operating System Data", "linux", k_num_linux_registers_s390x, - g_linux_regnums_s390x}, -}; -} - -#define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) - -// ---------------------------------------------------------------------------- -// Required ptrace defines. -// ---------------------------------------------------------------------------- - -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return llvm::make_unique<NativeRegisterContextLinux_s390x>(target_arch, - native_thread); -} - -// ---------------------------------------------------------------------------- -// NativeRegisterContextLinux_s390x members. -// ---------------------------------------------------------------------------- - -static RegisterInfoInterface * -CreateRegisterInfoInterface(const ArchSpec &target_arch) { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - return new RegisterContextLinux_s390x(target_arch); -} - -NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)) { - // Set up data about ranges of valid registers. - switch (target_arch.GetMachine()) { - case llvm::Triple::systemz: - m_reg_info.num_registers = k_num_registers_s390x; - m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; - m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; - m_reg_info.last_gpr = k_last_gpr_s390x; - m_reg_info.first_fpr = k_first_fpr_s390x; - m_reg_info.last_fpr = k_last_fpr_s390x; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - // Clear out the watchpoint state. - m_watchpoint_addr = LLDB_INVALID_ADDRESS; -} - -uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const { - uint32_t sets = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (IsRegisterSetAvailable(set_index)) - ++sets; - } - - return sets; -} - -uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - const RegisterSet *set = GetRegisterSet(set_index); - if (set) - count += set->num_registers; - } - return count; -} - -const RegisterSet * -NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const { - if (!IsRegisterSetAvailable(set_index)) - return nullptr; - - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::systemz: - return &g_reg_sets_s390x[set_index]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - - return nullptr; -} - -bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable( - uint32_t set_index) const { - return set_index < k_num_register_sets; -} - -bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const { - // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR - // register area. - return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; -} - -bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const { - return (m_reg_info.first_fpr <= reg_index && - reg_index <= m_reg_info.last_fpr); -} - -Status -NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg == LLDB_INVALID_REGNUM) - return Status("register \"%s\" is an internal-only lldb register, cannot " - "read directly", - reg_info->name); - - if (IsGPR(reg)) { - s390_regs regs; - Status error = DoReadGPR(®s, sizeof(regs)); - if (error.Fail()) - return error; - - uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); - switch (reg_info->byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return Status(); - } - - if (IsFPR(reg)) { - s390_fp_regs fp_regs; - Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); - if (error.Fail()) - return error; - - // byte_offset is just the offset within FPR, not the whole user area. - uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); - switch (reg_info->byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return Status(); - } - - if (reg == lldb_last_break_s390x) { - uint64_t last_break; - Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); - if (error.Fail()) - return error; - - reg_value.SetUInt64(last_break); - return Status(); - } - - if (reg == lldb_system_call_s390x) { - uint32_t system_call; - Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - if (error.Fail()) - return error; - - reg_value.SetUInt32(system_call); - return Status(); - } - - return Status("failed - register wasn't recognized"); -} - -Status NativeRegisterContextLinux_s390x::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg == LLDB_INVALID_REGNUM) - return Status("register \"%s\" is an internal-only lldb register, cannot " - "write directly", - reg_info->name); - - if (IsGPR(reg)) { - s390_regs regs; - Status error = DoReadGPR(®s, sizeof(regs)); - if (error.Fail()) - return error; - - uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); - switch (reg_info->byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return DoWriteGPR(®s, sizeof(regs)); - } - - if (IsFPR(reg)) { - s390_fp_regs fp_regs; - Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); - if (error.Fail()) - return error; - - // byte_offset is just the offset within fp_regs, not the whole user area. - uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); - switch (reg_info->byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return DoWriteFPR(&fp_regs, sizeof(fp_regs)); - } - - if (reg == lldb_last_break_s390x) { - return Status("The last break address is read-only"); - } - - if (reg == lldb_system_call_s390x) { - uint32_t system_call = reg_value.GetAsUInt32(); - return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - } - - return Status("failed - register wasn't recognized"); -} - -Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) { - error.SetErrorStringWithFormat( - "failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - return error; - } - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - - error = DoReadGPR(dst, sizeof(s390_regs)); - dst += sizeof(s390_regs); - if (error.Fail()) - return error; - - error = DoReadFPR(dst, sizeof(s390_fp_regs)); - dst += sizeof(s390_fp_regs); - if (error.Fail()) - return error; - - // Ignore errors if the regset is unsupported (happens on older kernels). - DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); - dst += 4; - - // To enable inferior function calls while the process is stopped in an - // interrupted system call, we need to clear the system call flag. It will be - // restored to its original value by WriteAllRegisterValues. Again we ignore - // error if the regset is unsupported. - uint32_t system_call = 0; - DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - - return error; -} - -Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - - error = DoWriteGPR(src, sizeof(s390_regs)); - src += sizeof(s390_regs); - if (error.Fail()) - return error; - - error = DoWriteFPR(src, sizeof(s390_fp_regs)); - src += sizeof(s390_fp_regs); - if (error.Fail()) - return error; - - // Ignore errors if the regset is unsupported (happens on older kernels). - DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); - src += 4; - - return error; -} - -Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( - uint32_t offset, const char *reg_name, uint32_t size, - RegisterValue &value) { - return Status("DoReadRegisterValue unsupported"); -} - -Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( - uint32_t offset, const char *reg_name, const RegisterValue &value) { - return Status("DoWriteRegisterValue unsupported"); -} - -Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, - void *buf, - size_t buf_size) { - ptrace_area parea; - parea.len = buf_size; - parea.process_addr = (addr_t)buf; - parea.kernel_addr = offset; - - return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, - m_thread.GetID(), &parea); -} - -Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, - const void *buf, - size_t buf_size) { - ptrace_area parea; - parea.len = buf_size; - parea.process_addr = (addr_t)buf; - parea.kernel_addr = offset; - - return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, - m_thread.GetID(), &parea); -} - -Status NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) { - assert(buf_size == sizeof(s390_regs)); - return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, - size_t buf_size) { - assert(buf_size == sizeof(s390_regs)); - return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { - assert(buf_size == sizeof(s390_fp_regs)); - return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, - size_t buf_size) { - assert(buf_size == sizeof(s390_fp_regs)); - return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, - void *buf, - size_t buf_size) { - struct iovec iov; - iov.iov_base = buf; - iov.iov_len = buf_size; - - return ReadRegisterSet(&iov, buf_size, regset); -} - -Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, - const void *buf, - size_t buf_size) { - struct iovec iov; - iov.iov_base = const_cast<void *>(buf); - iov.iov_len = buf_size; - - return WriteRegisterSet(&iov, buf_size, regset); -} - -Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - per_lowcore_bits per_lowcore; - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { - is_hit = false; - return Status(); - } - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), - &per_lowcore, sizeof(per_lowcore)); - if (error.Fail()) { - is_hit = false; - return error; - } - - is_hit = (per_lowcore.perc_storage_alteration == 1 && - per_lowcore.perc_store_real_address == 0); - - if (is_hit) { - // Do not report this watchpoint again. - memset(&per_lowcore, 0, sizeof(per_lowcore)); - PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, - sizeof(per_lowcore)); - } - - return Status(); -} - -Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - return error; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; - - return Status(); -} - -bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( - uint32_t wp_index) { - per_struct per_info; - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return false; - - per_info.control_regs.bits.em_storage_alteration = 0; - per_info.control_regs.bits.storage_alt_space_ctl = 0; - per_info.starting_addr = 0; - per_info.ending_addr = 0; - - error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return false; - - m_watchpoint_addr = LLDB_INVALID_ADDRESS; - return true; -} - -Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { - if (ClearHardwareWatchpoint(0)) - return Status(); - return Status("Clearing all hardware watchpoints failed."); -} - -uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - per_struct per_info; - - if (watch_flags != 0x1) - return LLDB_INVALID_INDEX32; - - if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) - return LLDB_INVALID_INDEX32; - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - per_info.control_regs.bits.em_storage_alteration = 1; - per_info.control_regs.bits.storage_alt_space_ctl = 1; - per_info.starting_addr = addr; - per_info.ending_addr = addr + size - 1; - - error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - m_watchpoint_addr = addr; - return 0; -} - -lldb::addr_t -NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - return m_watchpoint_addr; -} - -uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { - return 1; -} - -#endif // defined(__s390x__) && defined(__linux__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h deleted file mode 100644 index 57b1a0481512f..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h +++ /dev/null @@ -1,115 +0,0 @@ -//===-- NativeRegisterContextLinux_s390x.h ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__s390x__) && defined(__linux__) - -#ifndef lldb_NativeRegisterContextLinux_s390x_h -#define lldb_NativeRegisterContextLinux_s390x_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/RegisterContext_s390x.h" -#include "Plugins/Process/Utility/lldb-s390x-register-enums.h" - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_s390x : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_s390x(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - uint32_t GetUserRegisterCount() const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - -protected: - Status DoReadRegisterValue(uint32_t offset, const char *reg_name, - uint32_t size, RegisterValue &value) override; - - Status DoWriteRegisterValue(uint32_t offset, const char *reg_name, - const RegisterValue &value) override; - - Status DoReadGPR(void *buf, size_t buf_size) override; - - Status DoWriteGPR(void *buf, size_t buf_size) override; - - Status DoReadFPR(void *buf, size_t buf_size) override; - - Status DoWriteFPR(void *buf, size_t buf_size) override; - -private: - // Info about register ranges. - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - }; - - // Private member variables. - RegInfo m_reg_info; - lldb::addr_t m_watchpoint_addr; - - // Private member methods. - bool IsRegisterSetAvailable(uint32_t set_index) const; - - bool IsGPR(uint32_t reg_index) const; - - bool IsFPR(uint32_t reg_index) const; - - Status PeekUserArea(uint32_t offset, void *buf, size_t buf_size); - - Status PokeUserArea(uint32_t offset, const void *buf, size_t buf_size); - - Status DoReadRegisterSet(uint32_t regset, void *buf, size_t buf_size); - - Status DoWriteRegisterSet(uint32_t regset, const void *buf, size_t buf_size); -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_s390x_h - -#endif // defined(__s390x__) && defined(__linux__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp deleted file mode 100755 index 50bf29b094df0..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ /dev/null @@ -1,1213 +0,0 @@ -//===-- NativeRegisterContextLinux_x86_64.cpp ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__i386__) || defined(__x86_64__) - -#include "NativeRegisterContextLinux_x86_64.h" - -#include "lldb/Host/HostInfo.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" -#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" - -#include <linux/elf.h> - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -// ---------------------------------------------------------------------------- -// Private namespace. -// ---------------------------------------------------------------------------- - -namespace { -// x86 32-bit general purpose registers. -const uint32_t g_gpr_regnums_i386[] = { - lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, - lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, - lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, - lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386, - lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386, - lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386, - lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386, - lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - - 1 == - k_num_gpr_registers_i386, - "g_gpr_regnums_i386 has wrong number of register infos"); - -// x86 32-bit floating point registers. -const uint32_t g_fpu_regnums_i386[] = { - lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, - lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, - lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, - lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386, - lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386, - lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386, - lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386, - lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386, - lldb_xmm6_i386, lldb_xmm7_i386, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - - 1 == - k_num_fpr_registers_i386, - "g_fpu_regnums_i386 has wrong number of register infos"); - -// x86 32-bit AVX registers. -const uint32_t g_avx_regnums_i386[] = { - lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, - lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - - 1 == - k_num_avx_registers_i386, - " g_avx_regnums_i386 has wrong number of register infos"); - -// x64 32-bit MPX registers. -static const uint32_t g_mpx_regnums_i386[] = { - lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, lldb_bnd3_i386, - lldb_bndcfgu_i386, lldb_bndstatus_i386, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - - 1 == - k_num_mpx_registers_i386, - "g_mpx_regnums_x86_64 has wrong number of register infos"); - -// x86 64-bit general purpose registers. -static const uint32_t g_gpr_regnums_x86_64[] = { - lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, - lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, - lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, - lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, - lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, - lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, - lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64, - lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64, - lldb_r8d_x86_64, // Low 32 bits or r8 - lldb_r9d_x86_64, // Low 32 bits or r9 - lldb_r10d_x86_64, // Low 32 bits or r10 - lldb_r11d_x86_64, // Low 32 bits or r11 - lldb_r12d_x86_64, // Low 32 bits or r12 - lldb_r13d_x86_64, // Low 32 bits or r13 - lldb_r14d_x86_64, // Low 32 bits or r14 - lldb_r15d_x86_64, // Low 32 bits or r15 - lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64, - lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64, - lldb_r8w_x86_64, // Low 16 bits or r8 - lldb_r9w_x86_64, // Low 16 bits or r9 - lldb_r10w_x86_64, // Low 16 bits or r10 - lldb_r11w_x86_64, // Low 16 bits or r11 - lldb_r12w_x86_64, // Low 16 bits or r12 - lldb_r13w_x86_64, // Low 16 bits or r13 - lldb_r14w_x86_64, // Low 16 bits or r14 - lldb_r15w_x86_64, // Low 16 bits or r15 - lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64, - lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64, - lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64, - lldb_r8l_x86_64, // Low 8 bits or r8 - lldb_r9l_x86_64, // Low 8 bits or r9 - lldb_r10l_x86_64, // Low 8 bits or r10 - lldb_r11l_x86_64, // Low 8 bits or r11 - lldb_r12l_x86_64, // Low 8 bits or r12 - lldb_r13l_x86_64, // Low 8 bits or r13 - lldb_r14l_x86_64, // Low 8 bits or r14 - lldb_r15l_x86_64, // Low 8 bits or r15 - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - - 1 == - k_num_gpr_registers_x86_64, - "g_gpr_regnums_x86_64 has wrong number of register infos"); - -// x86 64-bit floating point registers. -static const uint32_t g_fpu_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - - 1 == - k_num_fpr_registers_x86_64, - "g_fpu_regnums_x86_64 has wrong number of register infos"); - -// x86 64-bit AVX registers. -static const uint32_t g_avx_regnums_x86_64[] = { - lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, - lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, - lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, - lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - - 1 == - k_num_avx_registers_x86_64, - "g_avx_regnums_x86_64 has wrong number of register infos"); - -// x86 64-bit MPX registers. -static const uint32_t g_mpx_regnums_x86_64[] = { - lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, - lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - - 1 == - k_num_mpx_registers_x86_64, - "g_mpx_regnums_x86_64 has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 }; - -// Register sets for x86 32-bit. -static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_i386, - g_gpr_regnums_i386}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, - g_fpu_regnums_i386}, - {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386, - g_avx_regnums_i386}, - { "Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, - g_mpx_regnums_i386}}; - -// Register sets for x86 64-bit. -static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, - g_gpr_regnums_x86_64}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, - g_fpu_regnums_x86_64}, - {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, - g_avx_regnums_x86_64}, - { "Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, - g_mpx_regnums_x86_64}}; -} - -#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR)) - -// ---------------------------------------------------------------------------- -// Required ptrace defines. -// ---------------------------------------------------------------------------- - -// Support ptrace extensions even when compiled without required kernel support -#ifndef NT_X86_XSTATE -#define NT_X86_XSTATE 0x202 -#endif -#ifndef NT_PRXFPREG -#define NT_PRXFPREG 0x46e62b7f -#endif - -// On x86_64 NT_PRFPREG is used to access the FXSAVE area. On i386, we need to -// use NT_PRXFPREG. -static inline unsigned int fxsr_regset(const ArchSpec &arch) { - return arch.GetAddressByteSize() == 8 ? NT_PRFPREG : NT_PRXFPREG; -} - -// ---------------------------------------------------------------------------- -// Required MPX define. -// ---------------------------------------------------------------------------- - -// Support MPX extensions also if compiled with compiler without MPX support. -#ifndef bit_MPX -#define bit_MPX 0x4000 -#endif - -// ---------------------------------------------------------------------------- -// XCR0 extended register sets masks. -// ---------------------------------------------------------------------------- -#define mask_XSTATE_AVX (1ULL << 2) -#define mask_XSTATE_BNDREGS (1ULL << 3) -#define mask_XSTATE_BNDCFG (1ULL << 4) -#define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG) - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return std::unique_ptr<NativeRegisterContextLinux>( - new NativeRegisterContextLinux_x86_64(target_arch, native_thread)); -} - -// ---------------------------------------------------------------------------- -// NativeRegisterContextLinux_x86_64 members. -// ---------------------------------------------------------------------------- - -static RegisterInfoInterface * -CreateRegisterInfoInterface(const ArchSpec &target_arch) { - if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { - // 32-bit hosts run with a RegisterContextLinux_i386 context. - return new RegisterContextLinux_i386(target_arch); - } else { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the - // x86_64 register context. - return new RegisterContextLinux_x86_64(target_arch); - } -} - -NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)), - m_xstate_type(XStateType::Invalid), m_fpr(), m_iovec(), m_ymm_set(), - m_mpx_set(), m_reg_info(), m_gpr_x86_64() { - // Set up data about ranges of valid registers. - switch (target_arch.GetMachine()) { - case llvm::Triple::x86: - m_reg_info.num_registers = k_num_registers_i386; - m_reg_info.num_gpr_registers = k_num_gpr_registers_i386; - m_reg_info.num_fpr_registers = k_num_fpr_registers_i386; - m_reg_info.num_avx_registers = k_num_avx_registers_i386; - m_reg_info.num_mpx_registers = k_num_mpx_registers_i386; - m_reg_info.last_gpr = k_last_gpr_i386; - m_reg_info.first_fpr = k_first_fpr_i386; - m_reg_info.last_fpr = k_last_fpr_i386; - m_reg_info.first_st = lldb_st0_i386; - m_reg_info.last_st = lldb_st7_i386; - m_reg_info.first_mm = lldb_mm0_i386; - m_reg_info.last_mm = lldb_mm7_i386; - m_reg_info.first_xmm = lldb_xmm0_i386; - m_reg_info.last_xmm = lldb_xmm7_i386; - m_reg_info.first_ymm = lldb_ymm0_i386; - m_reg_info.last_ymm = lldb_ymm7_i386; - m_reg_info.first_mpxr = lldb_bnd0_i386; - m_reg_info.last_mpxr = lldb_bnd3_i386; - m_reg_info.first_mpxc = lldb_bndcfgu_i386; - m_reg_info.last_mpxc = lldb_bndstatus_i386; - m_reg_info.first_dr = lldb_dr0_i386; - m_reg_info.gpr_flags = lldb_eflags_i386; - break; - case llvm::Triple::x86_64: - m_reg_info.num_registers = k_num_registers_x86_64; - m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64; - m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64; - m_reg_info.num_avx_registers = k_num_avx_registers_x86_64; - m_reg_info.num_mpx_registers = k_num_mpx_registers_x86_64; - m_reg_info.last_gpr = k_last_gpr_x86_64; - m_reg_info.first_fpr = k_first_fpr_x86_64; - m_reg_info.last_fpr = k_last_fpr_x86_64; - m_reg_info.first_st = lldb_st0_x86_64; - m_reg_info.last_st = lldb_st7_x86_64; - m_reg_info.first_mm = lldb_mm0_x86_64; - m_reg_info.last_mm = lldb_mm7_x86_64; - m_reg_info.first_xmm = lldb_xmm0_x86_64; - m_reg_info.last_xmm = lldb_xmm15_x86_64; - m_reg_info.first_ymm = lldb_ymm0_x86_64; - m_reg_info.last_ymm = lldb_ymm15_x86_64; - m_reg_info.first_mpxr = lldb_bnd0_x86_64; - m_reg_info.last_mpxr = lldb_bnd3_x86_64; - m_reg_info.first_mpxc = lldb_bndcfgu_x86_64; - m_reg_info.last_mpxc = lldb_bndstatus_x86_64; - m_reg_info.first_dr = lldb_dr0_x86_64; - m_reg_info.gpr_flags = lldb_rflags_x86_64; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - // Initialize m_iovec to point to the buffer and buffer size using the - // conventions of Berkeley style UIO structures, as required by PTRACE - // extensions. - m_iovec.iov_base = &m_fpr; - m_iovec.iov_len = sizeof(m_fpr); - - // Clear out the FPR state. - ::memset(&m_fpr, 0, sizeof(m_fpr)); - - // Store byte offset of fctrl (i.e. first register of FPR) - const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl"); - m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset; -} - -// CONSIDER after local and llgs debugging are merged, register set support can -// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. -uint32_t NativeRegisterContextLinux_x86_64::GetRegisterSetCount() const { - uint32_t sets = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (IsRegisterSetAvailable(set_index)) - ++sets; - } - - return sets; -} - -uint32_t NativeRegisterContextLinux_x86_64::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - const RegisterSet *set = GetRegisterSet(set_index); - if (set) - count += set->num_registers; - } - return count; -} - -const RegisterSet * -NativeRegisterContextLinux_x86_64::GetRegisterSet(uint32_t set_index) const { - if (!IsRegisterSetAvailable(set_index)) - return nullptr; - - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86: - return &g_reg_sets_i386[set_index]; - case llvm::Triple::x86_64: - return &g_reg_sets_x86_64[set_index]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - - return nullptr; -} - -Status -NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg == LLDB_INVALID_REGNUM) { - // This is likely an internal register for lldb use only and should not be - // directly queried. - error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " - "register, cannot read directly", - reg_info->name); - return error; - } - - if (IsFPR(reg) || IsAVX(reg) || IsMPX(reg)) { - error = ReadFPR(); - if (error.Fail()) - return error; - } 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]; - } - - error = ReadRegisterRaw(full_reg, reg_value); - - if (error.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)) - reg_value.SetUInt64(reg_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 (reg_value.GetByteSize() > reg_info->byte_size) - reg_value.SetType(reg_info); - } - return error; - } - - if (reg_info->encoding == lldb::eEncodingVector) { - lldb::ByteOrder byte_order = GetByteOrder(); - - if (byte_order != lldb::eByteOrderInvalid) { - if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - reg_value.SetBytes(m_fpr.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) - reg_value.SetBytes(m_fpr.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) - reg_value.SetBytes(m_fpr.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 (CopyXSTATEtoYMM(reg, byte_order)) - reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, - reg_info->byte_size, byte_order); - else { - error.SetErrorString("failed to copy ymm register value"); - return error; - } - } - if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) { - if (CopyXSTATEtoMPX(reg)) - reg_value.SetBytes(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, - reg_info->byte_size, byte_order); - else { - error.SetErrorString("failed to copy mpx register value"); - return error; - } - } - if (reg >= m_reg_info.first_mpxc && reg <= m_reg_info.last_mpxc) { - if (CopyXSTATEtoMPX(reg)) - reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, - reg_info->byte_size, byte_order); - else { - error.SetErrorString("failed to copy mpx register value"); - return error; - } - } - - if (reg_value.GetType() != RegisterValue::eTypeBytes) - error.SetErrorString( - "write failed - type was expected to be RegisterValue::eTypeBytes"); - - return error; - } - - error.SetErrorString("byte order is invalid"); - return error; - } - - // Get pointer to m_fpr.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(PTRACE_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: - reg_value.SetUInt8(*(uint8_t *)src); - break; - case 2: - reg_value.SetUInt16(*(uint16_t *)src); - break; - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - - return error; -} - -void NativeRegisterContextLinux_x86_64::UpdateXSTATEforWrite( - uint32_t reg_index) { - XSAVE_HDR::XFeature &xstate_bv = m_fpr.xsave.header.xstate_bv; - if (IsFPR(reg_index)) { - // IsFPR considers both %st and %xmm registers as floating point, but these - // map to two features. Set both flags, just in case. - xstate_bv |= XSAVE_HDR::XFeature::FP | XSAVE_HDR::XFeature::SSE; - } else if (IsAVX(reg_index)) { - // Lower bytes of some %ymm registers are shared with %xmm registers. - xstate_bv |= XSAVE_HDR::XFeature::YMM | XSAVE_HDR::XFeature::SSE; - } else if (IsMPX(reg_index)) { - // MPX registers map to two XSAVE features. - xstate_bv |= XSAVE_HDR::XFeature::BNDREGS | XSAVE_HDR::XFeature::BNDCSR; - } -} - -Status NativeRegisterContextLinux_x86_64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - assert(reg_info && "reg_info is null"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - UpdateXSTATEforWrite(reg_index); - - if (IsGPR(reg_index)) - return WriteRegisterRaw(reg_index, reg_value); - - if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) { - if (reg_info->encoding == lldb::eEncodingVector) { - if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st) - ::memcpy(m_fpr.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - - if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm) - ::memcpy(m_fpr.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - - if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm) - ::memcpy(m_fpr.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - - if (reg_index >= m_reg_info.first_ymm && - reg_index <= m_reg_info.last_ymm) { - // Store ymm register content, and split into the register halves in - // xmm.bytes and ymmh.bytes - ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - if (!CopyYMMtoXSTATE(reg_index, GetByteOrder())) - return Status("CopyYMMtoXSTATE() failed"); - } - - if (reg_index >= m_reg_info.first_mpxr && - reg_index <= m_reg_info.last_mpxr) { - ::memcpy(m_mpx_set.mpxr[reg_index - m_reg_info.first_mpxr].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - if (!CopyMPXtoXSTATE(reg_index)) - return Status("CopyMPXtoXSTATE() failed"); - } - - if (reg_index >= m_reg_info.first_mpxc && - reg_index <= m_reg_info.last_mpxc) { - ::memcpy(m_mpx_set.mpxc[reg_index - m_reg_info.first_mpxc].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); - if (!CopyMPXtoXSTATE(reg_index)) - return Status("CopyMPXtoXSTATE() failed"); - } - } else { - // Get pointer to m_fpr.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(PTRACE_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 = reg_value.GetAsUInt8(); - break; - case 2: - *(uint16_t *)dst = reg_value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled register data size %" PRIu32, - reg_info->byte_size); - } - } - - Status error = WriteFPR(); - if (error.Fail()) - return error; - - if (IsAVX(reg_index)) { - if (!CopyYMMtoXSTATE(reg_index, GetByteOrder())) - return Status("CopyYMMtoXSTATE() failed"); - } - - if (IsMPX(reg_index)) { - if (!CopyMPXtoXSTATE(reg_index)) - return Status("CopyMPXtoXSTATE() failed"); - } - return Status(); - } - return Status("failed - register wasn't recognized to be a GPR or an FPR, " - "write strategy unknown"); -} - -Status NativeRegisterContextLinux_x86_64::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - error = ReadGPR(); - if (error.Fail()) - return error; - - error = ReadFPR(); - if (error.Fail()) - return error; - - uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); - dst += GetRegisterInfoInterface().GetGPRSize(); - if (m_xstate_type == XStateType::FXSAVE) - ::memcpy(dst, &m_fpr.fxsave, sizeof(m_fpr.fxsave)); - else if (m_xstate_type == XStateType::XSAVE) { - lldb::ByteOrder byte_order = GetByteOrder(); - - if (IsCPUFeatureAvailable(RegSet::avx)) { - // Assemble the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; - ++reg) { - if (!CopyXSTATEtoYMM(reg, byte_order)) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s " - "CopyXSTATEtoYMM() failed for reg num " - "%" PRIu32, - __FUNCTION__, reg); - return error; - } - } - } - - if (IsCPUFeatureAvailable(RegSet::mpx)) { - for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; - ++reg) { - if (!CopyXSTATEtoMPX(reg)) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s " - "CopyXSTATEtoMPX() failed for reg num " - "%" PRIu32, - __FUNCTION__, reg); - return error; - } - } - } - // Copy the extended register state including the assembled ymm registers. - ::memcpy(dst, &m_fpr, sizeof(m_fpr)); - } else { - assert(false && "how do we save the floating point registers?"); - error.SetErrorString("unsure how to save the floating point registers"); - } - /** The following code is specific to Linux x86 based architectures, - * where the register orig_eax (32 bit)/orig_rax (64 bit) is set to - * -1 to solve the bug 23659, such a setting prevents the automatic - * decrement of the instruction pointer which was causing the SIGILL - * exception. - * **/ - - RegisterValue value((uint64_t)-1); - const RegisterInfo *reg_info = - GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax"); - if (reg_info == nullptr) - reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax"); - - if (reg_info != nullptr) - return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, value); - - return error; -} - -Status NativeRegisterContextLinux_x86_64::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormatv( - "data_sp contained mismatched data size, expected {0}, actual {1}", - REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize()); - - error = WriteGPR(); - if (error.Fail()) - return error; - - src += GetRegisterInfoInterface().GetGPRSize(); - if (m_xstate_type == XStateType::FXSAVE) - ::memcpy(&m_fpr.fxsave, src, sizeof(m_fpr.fxsave)); - else if (m_xstate_type == XStateType::XSAVE) - ::memcpy(&m_fpr.xsave, src, sizeof(m_fpr.xsave)); - - error = WriteFPR(); - if (error.Fail()) - return error; - - if (m_xstate_type == XStateType::XSAVE) { - lldb::ByteOrder byte_order = GetByteOrder(); - - if (IsCPUFeatureAvailable(RegSet::avx)) { - // Parse the YMM register content from the register halves. - for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; - ++reg) { - if (!CopyYMMtoXSTATE(reg, byte_order)) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s " - "CopyYMMtoXSTATE() failed for reg num " - "%" PRIu32, - __FUNCTION__, reg); - return error; - } - } - } - - if (IsCPUFeatureAvailable(RegSet::mpx)) { - for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; - ++reg) { - if (!CopyMPXtoXSTATE(reg)) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s " - "CopyMPXtoXSTATE() failed for reg num " - "%" PRIu32, - __FUNCTION__, reg); - return error; - } - } - } - } - - return error; -} - -bool NativeRegisterContextLinux_x86_64::IsCPUFeatureAvailable( - RegSet feature_code) const { - if (m_xstate_type == XStateType::Invalid) { - if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail()) - return false; - } - switch (feature_code) { - case RegSet::gpr: - case RegSet::fpu: - return true; - case RegSet::avx: // Check if CPU has AVX and if there is kernel support, by - // reading in the XCR0 area of XSAVE. - if ((m_fpr.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX) - return true; - break; - case RegSet::mpx: // Check if CPU has MPX and if there is kernel support, by - // reading in the XCR0 area of XSAVE. - if ((m_fpr.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX) - return true; - break; - } - return false; -} - -bool NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable( - uint32_t set_index) const { - uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets; - - switch (static_cast<RegSet>(set_index)) { - case RegSet::gpr: - case RegSet::fpu: - return (set_index < num_sets); - case RegSet::avx: - return IsCPUFeatureAvailable(RegSet::avx); - case RegSet::mpx: - return IsCPUFeatureAvailable(RegSet::mpx); - } - return false; -} - -bool NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const { - // GPRs come first. - return reg_index <= m_reg_info.last_gpr; -} - -bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const { - return (m_reg_info.first_fpr <= reg_index && - reg_index <= m_reg_info.last_fpr); -} - -Status NativeRegisterContextLinux_x86_64::WriteFPR() { - switch (m_xstate_type) { - case XStateType::FXSAVE: - return WriteRegisterSet( - &m_iovec, sizeof(m_fpr.fxsave), - fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture())); - case XStateType::XSAVE: - return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xsave), NT_X86_XSTATE); - default: - return Status("Unrecognized FPR type."); - } -} - -bool NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const { - if (!IsCPUFeatureAvailable(RegSet::avx)) - return false; - return (m_reg_info.first_ymm <= reg_index && - reg_index <= m_reg_info.last_ymm); -} - -bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM( - uint32_t reg_index, lldb::ByteOrder byte_order) { - if (!IsAVX(reg_index)) - return false; - - if (byte_order == lldb::eByteOrderLittle) { - ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, - m_fpr.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes, - sizeof(XMMReg)); - ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + - sizeof(XMMReg), - m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, - sizeof(YMMHReg)); - return true; - } - - if (byte_order == lldb::eByteOrderBig) { - ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + - sizeof(XMMReg), - m_fpr.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes, - sizeof(XMMReg)); - ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, - m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, - sizeof(YMMHReg)); - return true; - } - return false; // unsupported or invalid byte order -} - -bool NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE( - uint32_t reg, lldb::ByteOrder byte_order) { - if (!IsAVX(reg)) - return false; - - if (byte_order == lldb::eByteOrderLittle) { - ::memcpy(m_fpr.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, - m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(XMMReg)); - ::memcpy(m_fpr.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, - m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), - sizeof(YMMHReg)); - return true; - } - - if (byte_order == lldb::eByteOrderBig) { - ::memcpy(m_fpr.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, - m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), - sizeof(XMMReg)); - ::memcpy(m_fpr.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, - m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(YMMHReg)); - return true; - } - return false; // unsupported or invalid byte order -} - -void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() { - switch (m_xstate_type) { - case XStateType::FXSAVE: - return &m_fpr.fxsave; - case XStateType::XSAVE: - return &m_iovec; - default: - return nullptr; - } -} - -size_t NativeRegisterContextLinux_x86_64::GetFPRSize() { - switch (m_xstate_type) { - case XStateType::FXSAVE: - return sizeof(m_fpr.fxsave); - case XStateType::XSAVE: - return sizeof(m_iovec); - default: - return 0; - } -} - -Status NativeRegisterContextLinux_x86_64::ReadFPR() { - Status error; - - // Probe XSAVE and if it is not supported fall back to FXSAVE. - if (m_xstate_type != XStateType::FXSAVE) { - error = ReadRegisterSet(&m_iovec, sizeof(m_fpr.xsave), NT_X86_XSTATE); - if (!error.Fail()) { - m_xstate_type = XStateType::XSAVE; - return error; - } - } - error = ReadRegisterSet( - &m_iovec, sizeof(m_fpr.xsave), - fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture())); - if (!error.Fail()) { - m_xstate_type = XStateType::FXSAVE; - return error; - } - return Status("Unrecognized FPR type."); -} - -bool NativeRegisterContextLinux_x86_64::IsMPX(uint32_t reg_index) const { - if (!IsCPUFeatureAvailable(RegSet::mpx)) - return false; - return (m_reg_info.first_mpxr <= reg_index && - reg_index <= m_reg_info.last_mpxc); -} - -bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) { - if (!IsMPX(reg)) - return false; - - if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) { - ::memcpy(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, - m_fpr.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes, - sizeof(MPXReg)); - } else { - ::memcpy(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, - m_fpr.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, - sizeof(MPXCsr)); - } - return true; -} - -bool NativeRegisterContextLinux_x86_64::CopyMPXtoXSTATE(uint32_t reg) { - if (!IsMPX(reg)) - return false; - - if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) { - ::memcpy(m_fpr.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes, - m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, sizeof(MPXReg)); - } else { - ::memcpy(m_fpr.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, - m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr)); - } - return true; -} - -Status NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) { - is_hit = false; - return error; - } - - uint64_t status_bits = reg_value.GetAsUInt64(); - - is_hit = status_bits & (1 << wp_index); - - return error; -} - -Status NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - return error; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - Status error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) { - is_vacant = false; - return error; - } - - uint64_t control_bits = reg_value.GetAsUInt64(); - - is_vacant = !(control_bits & (1 << (2 * wp_index))); - - return error; -} - -Status NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // Read only watchpoints aren't supported on x86_64. Fall back to read/write - // waitchpoints instead. - // TODO: Add logic to detect when a write happens and ignore that watchpoint - // hit. - if (watch_flags == 0x2) - watch_flags = 0x3; - - if (watch_flags != 0x1 && watch_flags != 0x3) - return Status("Invalid read/write bits for watchpoint"); - - if (size != 1 && size != 2 && size != 4 && size != 8) - return Status("Invalid size for watchpoint"); - - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (error.Fail()) - return error; - if (!is_vacant) - return Status("Watchpoint index not vacant"); - - RegisterValue reg_value; - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return error; - - // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 - uint64_t enable_bit = 1 << (2 * wp_index); - - // set bits 16-17, 20-21, 24-25, or 28-29 - // with 0b01 for write, and 0b11 for read/write - uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); - - // set bits 18-19, 22-23, 26-27, or 30-31 - // with 0b00, 0b01, 0b10, or 0b11 - // for 1, 2, 8 (if supported), or 4 bytes, respectively - uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); - - uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - - control_bits |= enable_bit | rw_bits | size_bits; - - error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr)); - if (error.Fail()) - return error; - - error = - WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)); - if (error.Fail()) - return error; - - error.Clear(); - return error; -} - -bool NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - RegisterValue reg_value; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of - // the debug status register (DR6) - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) - return false; - uint64_t bit_mask = 1 << wp_index; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits)); - if (error.Fail()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, - // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register - // (DR7) - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return false; - bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)) - .Success(); -} - -Status NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints() { - RegisterValue reg_value; - - // clear bits {0-4} of the debug status register (DR6) - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) - return error; - uint64_t bit_mask = 0xF; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits)); - if (error.Fail()) - return error; - - // clear bits {0-7,16-31} of the debug control register (DR7) - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return error; - bit_mask = 0xFF | (0xFFFF << 16); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)); -} - -uint32_t NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (is_vacant) { - error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); - if (error.Success()) - return wp_index; - } - if (error.Fail() && log) { - log->Printf("NativeRegisterContextLinux_x86_64::%s Error: %s", - __FUNCTION__, error.AsCString()); - } - } - return LLDB_INVALID_INDEX32; -} - -lldb::addr_t -NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - RegisterValue reg_value; - if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail()) - return LLDB_INVALID_ADDRESS; - return reg_value.GetAsUInt64(); -} - -uint32_t NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints() { - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} - -#endif // defined(__i386__) || defined(__x86_64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h deleted file mode 100644 index 9dcf82f50a458..0000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ /dev/null @@ -1,149 +0,0 @@ -//===-- NativeRegisterContextLinux_x86_64.h ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__i386__) || defined(__x86_64__) - -#ifndef lldb_NativeRegisterContextLinux_x86_64_h -#define lldb_NativeRegisterContextLinux_x86_64_h - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Utility/RegisterContext_x86.h" -#include "Plugins/Process/Utility/lldb-x86-register-enums.h" -#include <sys/uio.h> - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux { -public: - NativeRegisterContextLinux_x86_64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); - - uint32_t GetRegisterSetCount() const override; - - const RegisterSet *GetRegisterSet(uint32_t set_index) const override; - - uint32_t GetUserRegisterCount() const override; - - Status ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - Status WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - - Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - -protected: - void *GetGPRBuffer() override { return &m_gpr_x86_64; } - - void *GetFPRBuffer() override; - - size_t GetFPRSize() override; - - Status ReadFPR() override; - - Status WriteFPR() override; - -private: - // Private member types. - enum class XStateType { Invalid, FXSAVE, XSAVE }; - enum class RegSet { gpr, fpu, avx, mpx }; - - // Info about register ranges. - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - uint32_t num_avx_registers; - uint32_t num_mpx_registers; - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - uint32_t first_st; - uint32_t last_st; - uint32_t first_mm; - uint32_t last_mm; - uint32_t first_xmm; - uint32_t last_xmm; - uint32_t first_ymm; - uint32_t last_ymm; - uint32_t first_mpxr; - uint32_t last_mpxr; - uint32_t first_mpxc; - uint32_t last_mpxc; - uint32_t first_dr; - uint32_t gpr_flags; - }; - - // Private member variables. - mutable XStateType m_xstate_type; - FPR m_fpr; // Extended States Area, named FPR for historical reasons. - struct iovec m_iovec; - YMM m_ymm_set; - MPX m_mpx_set; - RegInfo m_reg_info; - uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64]; - uint32_t m_fctrl_offset_in_userarea; - - // Private member methods. - bool IsCPUFeatureAvailable(RegSet feature_code) const; - - bool IsRegisterSetAvailable(uint32_t set_index) const; - - bool IsGPR(uint32_t reg_index) const; - - bool IsFPR(uint32_t reg_index) const; - - bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order); - - bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); - - bool IsAVX(uint32_t reg_index) const; - - bool CopyXSTATEtoMPX(uint32_t reg); - - bool CopyMPXtoXSTATE(uint32_t reg); - - bool IsMPX(uint32_t reg_index) const; - - void UpdateXSTATEforWrite(uint32_t reg_index); -}; - -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h - -#endif // defined(__i386__) || defined(__x86_64__) diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp deleted file mode 100644 index b64689c9d17b0..0000000000000 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ /dev/null @@ -1,451 +0,0 @@ -//===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "NativeThreadLinux.h" - -#include <signal.h> -#include <sstream> - -#include "NativeProcessLinux.h" -#include "NativeRegisterContextLinux.h" -#include "SingleStepCheck.h" - -#include "lldb/Host/HostNativeThread.h" -#include "lldb/Host/linux/Ptrace.h" -#include "lldb/Host/linux/Support.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" -#include "lldb/lldb-enumerations.h" - -#include "llvm/ADT/SmallString.h" - -#include "Plugins/Process/POSIX/CrashReason.h" - -#include <sys/syscall.h> -// Try to define a macro to encapsulate the tgkill syscall -#define tgkill(pid, tid, sig) \ - syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \ - sig) - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -namespace { -void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, - const char *const header) { - switch (stop_info.reason) { - case eStopReasonNone: - log.Printf("%s: %s no stop reason", __FUNCTION__, header); - return; - case eStopReasonTrace: - log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, - stop_info.details.signal.signo); - return; - case eStopReasonBreakpoint: - log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, - header, stop_info.details.signal.signo); - return; - case eStopReasonWatchpoint: - log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, - header, stop_info.details.signal.signo); - return; - case eStopReasonSignal: - log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, - stop_info.details.signal.signo); - return; - case eStopReasonException: - log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, - stop_info.details.exception.type); - return; - case eStopReasonExec: - log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, - stop_info.details.signal.signo); - return; - case eStopReasonPlanComplete: - log.Printf("%s: %s plan complete", __FUNCTION__, header); - return; - case eStopReasonThreadExiting: - log.Printf("%s: %s thread exiting", __FUNCTION__, header); - return; - case eStopReasonInstrumentation: - log.Printf("%s: %s instrumentation", __FUNCTION__, header); - return; - default: - log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, - static_cast<uint32_t>(stop_info.reason)); - } -} -} - -NativeThreadLinux::NativeThreadLinux(NativeProcessLinux &process, - lldb::tid_t tid) - : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), - m_stop_info(), - m_reg_context_up( - NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - process.GetArchitecture(), *this)), - m_stop_description() {} - -std::string NativeThreadLinux::GetName() { - NativeProcessLinux &process = GetProcess(); - - auto BufferOrError = getProcFile(process.GetID(), GetID(), "comm"); - if (!BufferOrError) - return ""; - return BufferOrError.get()->getBuffer().rtrim('\n'); -} - -lldb::StateType NativeThreadLinux::GetState() { return m_state; } - -bool NativeThreadLinux::GetStopReason(ThreadStopInfo &stop_info, - std::string &description) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - - description.clear(); - - switch (m_state) { - case eStateStopped: - case eStateCrashed: - case eStateExited: - case eStateSuspended: - case eStateUnloaded: - if (log) - LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:"); - stop_info = m_stop_info; - description = m_stop_description; - if (log) - LogThreadStopInfo(*log, stop_info, "returned stop_info:"); - - return true; - - case eStateInvalid: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateRunning: - case eStateStepping: - case eStateDetached: - if (log) { - log->Printf("NativeThreadLinux::%s tid %" PRIu64 - " in state %s cannot answer stop reason", - __FUNCTION__, GetID(), StateAsCString(m_state)); - } - return false; - } - llvm_unreachable("unhandled StateType!"); -} - -Status NativeThreadLinux::SetWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags, bool hardware) { - if (!hardware) - return Status("not implemented"); - if (m_state == eStateLaunching) - return Status(); - Status error = RemoveWatchpoint(addr); - if (error.Fail()) - return error; - uint32_t wp_index = - m_reg_context_up->SetHardwareWatchpoint(addr, size, watch_flags); - if (wp_index == LLDB_INVALID_INDEX32) - return Status("Setting hardware watchpoint failed."); - m_watchpoint_index_map.insert({addr, wp_index}); - return Status(); -} - -Status NativeThreadLinux::RemoveWatchpoint(lldb::addr_t addr) { - auto wp = m_watchpoint_index_map.find(addr); - if (wp == m_watchpoint_index_map.end()) - return Status(); - uint32_t wp_index = wp->second; - m_watchpoint_index_map.erase(wp); - if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) - return Status(); - return Status("Clearing hardware watchpoint failed."); -} - -Status NativeThreadLinux::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - if (m_state == eStateLaunching) - return Status(); - - Status error = RemoveHardwareBreakpoint(addr); - if (error.Fail()) - return error; - - uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); - - if (bp_index == LLDB_INVALID_INDEX32) - return Status("Setting hardware breakpoint failed."); - - m_hw_break_index_map.insert({addr, bp_index}); - return Status(); -} - -Status NativeThreadLinux::RemoveHardwareBreakpoint(lldb::addr_t addr) { - auto bp = m_hw_break_index_map.find(addr); - if (bp == m_hw_break_index_map.end()) - return Status(); - - uint32_t bp_index = bp->second; - if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { - m_hw_break_index_map.erase(bp); - return Status(); - } - - return Status("Clearing hardware breakpoint failed."); -} - -Status NativeThreadLinux::Resume(uint32_t signo) { - const StateType new_state = StateType::eStateRunning; - MaybeLogStateChange(new_state); - m_state = new_state; - - m_stop_info.reason = StopReason::eStopReasonNone; - m_stop_description.clear(); - - // If watchpoints have been set, but none on this thread, then this is a new - // thread. So set all existing watchpoints. - if (m_watchpoint_index_map.empty()) { - NativeProcessLinux &process = GetProcess(); - - const auto &watchpoint_map = process.GetWatchpointMap(); - m_reg_context_up->ClearAllHardwareWatchpoints(); - for (const auto &pair : watchpoint_map) { - const auto &wp = pair.second; - SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); - } - } - - // Set all active hardware breakpoint on all threads. - if (m_hw_break_index_map.empty()) { - NativeProcessLinux &process = GetProcess(); - - const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); - m_reg_context_up->ClearAllHardwareBreakpoints(); - for (const auto &pair : hw_breakpoint_map) { - const auto &bp = pair.second; - SetHardwareBreakpoint(bp.m_addr, bp.m_size); - } - } - - intptr_t data = 0; - - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - data = signo; - - return NativeProcessLinux::PtraceWrapper(PTRACE_CONT, GetID(), nullptr, - reinterpret_cast<void *>(data)); -} - -Status NativeThreadLinux::SingleStep(uint32_t signo) { - const StateType new_state = StateType::eStateStepping; - MaybeLogStateChange(new_state); - m_state = new_state; - m_stop_info.reason = StopReason::eStopReasonNone; - - if(!m_step_workaround) { - // If we already hava a workaround inplace, don't reset it. Otherwise, the - // destructor of the existing instance will run after the new instance has - // fetched the cpu mask, and the thread will end up with the wrong mask. - m_step_workaround = SingleStepWorkaround::Get(m_tid); - } - - intptr_t data = 0; - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - data = signo; - - // If hardware single-stepping is not supported, we just do a continue. The - // breakpoint on the next instruction has been setup in - // NativeProcessLinux::Resume. - return NativeProcessLinux::PtraceWrapper( - GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP - : PTRACE_CONT, - m_tid, nullptr, reinterpret_cast<void *>(data)); -} - -void NativeThreadLinux::SetStoppedBySignal(uint32_t signo, - const siginfo_t *info) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("NativeThreadLinux::%s called with signal 0x%02" PRIx32, - __FUNCTION__, signo); - - SetStopped(); - - m_stop_info.reason = StopReason::eStopReasonSignal; - m_stop_info.details.signal.signo = signo; - - m_stop_description.clear(); - if (info) { - switch (signo) { - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - // In case of MIPS64 target, SI_KERNEL is generated for invalid 64bit - // address. - const auto reason = - (info->si_signo == SIGBUS && info->si_code == SI_KERNEL) - ? CrashReason::eInvalidAddress - : GetCrashReason(*info); - m_stop_description = GetCrashReasonString(reason, *info); - break; - } - } -} - -bool NativeThreadLinux::IsStopped(int *signo) { - if (!StateIsStoppedState(m_state, false)) - return false; - - // If we are stopped by a signal, return the signo. - if (signo && m_state == StateType::eStateStopped && - m_stop_info.reason == StopReason::eStopReasonSignal) { - *signo = m_stop_info.details.signal.signo; - } - - // Regardless, we are stopped. - return true; -} - -void NativeThreadLinux::SetStopped() { - if (m_state == StateType::eStateStepping) - m_step_workaround.reset(); - - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange(new_state); - m_state = new_state; - m_stop_description.clear(); -} - -void NativeThreadLinux::SetStoppedByExec() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("NativeThreadLinux::%s()", __FUNCTION__); - - SetStopped(); - - m_stop_info.reason = StopReason::eStopReasonExec; - m_stop_info.details.signal.signo = SIGSTOP; -} - -void NativeThreadLinux::SetStoppedByBreakpoint() { - SetStopped(); - - m_stop_info.reason = StopReason::eStopReasonBreakpoint; - m_stop_info.details.signal.signo = SIGTRAP; - m_stop_description.clear(); -} - -void NativeThreadLinux::SetStoppedByWatchpoint(uint32_t wp_index) { - SetStopped(); - - lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); - - std::ostringstream ostr; - ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; - ostr << wp_index; - - /* - * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For - * example: - * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at - * 'm', then - * watch exception is generated even when 'n' is read/written. To handle this - * case, - * find the base address of the load/store instruction and append it in the - * stop-info - * packet. - */ - ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); - - m_stop_description = ostr.str(); - - m_stop_info.reason = StopReason::eStopReasonWatchpoint; - m_stop_info.details.signal.signo = SIGTRAP; -} - -bool NativeThreadLinux::IsStoppedAtBreakpoint() { - return GetState() == StateType::eStateStopped && - m_stop_info.reason == StopReason::eStopReasonBreakpoint; -} - -bool NativeThreadLinux::IsStoppedAtWatchpoint() { - return GetState() == StateType::eStateStopped && - m_stop_info.reason == StopReason::eStopReasonWatchpoint; -} - -void NativeThreadLinux::SetStoppedByTrace() { - SetStopped(); - - m_stop_info.reason = StopReason::eStopReasonTrace; - m_stop_info.details.signal.signo = SIGTRAP; -} - -void NativeThreadLinux::SetStoppedWithNoReason() { - SetStopped(); - - m_stop_info.reason = StopReason::eStopReasonNone; - m_stop_info.details.signal.signo = 0; -} - -void NativeThreadLinux::SetExited() { - const StateType new_state = StateType::eStateExited; - MaybeLogStateChange(new_state); - m_state = new_state; - - m_stop_info.reason = StopReason::eStopReasonThreadExiting; -} - -Status NativeThreadLinux::RequestStop() { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - - NativeProcessLinux &process = GetProcess(); - - lldb::pid_t pid = process.GetID(); - lldb::tid_t tid = GetID(); - - if (log) - log->Printf("NativeThreadLinux::%s requesting thread stop(pid: %" PRIu64 - ", tid: %" PRIu64 ")", - __FUNCTION__, pid, tid); - - Status err; - errno = 0; - if (::tgkill(pid, tid, SIGSTOP) != 0) { - err.SetErrorToErrno(); - if (log) - log->Printf("NativeThreadLinux::%s tgkill(%" PRIu64 ", %" PRIu64 - ", SIGSTOP) failed: %s", - __FUNCTION__, pid, tid, err.AsCString()); - } - - return err; -} - -void NativeThreadLinux::MaybeLogStateChange(lldb::StateType new_state) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - // If we're not logging, we're done. - if (!log) - return; - - // If this is a state change to the same state, we're done. - lldb::StateType old_state = m_state; - if (new_state == old_state) - return; - - LLDB_LOG(log, "pid={0}, tid={1}: changing from state {2} to {3}", - m_process.GetID(), GetID(), old_state, new_state); -} - -NativeProcessLinux &NativeThreadLinux::GetProcess() { - return static_cast<NativeProcessLinux &>(m_process); -} diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.h b/source/Plugins/Process/Linux/NativeThreadLinux.h deleted file mode 100644 index a7c4e982012d2..0000000000000 --- a/source/Plugins/Process/Linux/NativeThreadLinux.h +++ /dev/null @@ -1,119 +0,0 @@ -//===-- NativeThreadLinux.h ----------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_NativeThreadLinux_H_ -#define liblldb_NativeThreadLinux_H_ - -#include "Plugins/Process/Linux/NativeRegisterContextLinux.h" -#include "Plugins/Process/Linux/SingleStepCheck.h" -#include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/lldb-private-forward.h" - -#include <csignal> -#include <map> -#include <memory> -#include <string> - -namespace lldb_private { -namespace process_linux { - -class NativeProcessLinux; - -class NativeThreadLinux : public NativeThreadProtocol { - friend class NativeProcessLinux; - -public: - NativeThreadLinux(NativeProcessLinux &process, lldb::tid_t tid); - - // --------------------------------------------------------------------- - // NativeThreadProtocol Interface - // --------------------------------------------------------------------- - std::string GetName() override; - - lldb::StateType GetState() override; - - bool GetStopReason(ThreadStopInfo &stop_info, - std::string &description) override; - - NativeRegisterContextLinux &GetRegisterContext() override { - return *m_reg_context_up; - } - - Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, - bool hardware) override; - - Status RemoveWatchpoint(lldb::addr_t addr) override; - - Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; - -private: - // --------------------------------------------------------------------- - // Interface for friend classes - // --------------------------------------------------------------------- - - /// Resumes the thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status Resume(uint32_t signo); - - /// Single steps the thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. - Status SingleStep(uint32_t signo); - - 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); - - void SetStoppedByExec(); - - void SetStoppedByBreakpoint(); - - void SetStoppedByWatchpoint(uint32_t wp_index); - - bool IsStoppedAtBreakpoint(); - - bool IsStoppedAtWatchpoint(); - - void SetStoppedByTrace(); - - void SetStoppedWithNoReason(); - - void SetExited(); - - Status RequestStop(); - - // --------------------------------------------------------------------- - // Private interface - // --------------------------------------------------------------------- - void MaybeLogStateChange(lldb::StateType new_state); - - NativeProcessLinux &GetProcess(); - - void SetStopped(); - - // --------------------------------------------------------------------- - // Member Variables - // --------------------------------------------------------------------- - lldb::StateType m_state; - ThreadStopInfo m_stop_info; - std::unique_ptr<NativeRegisterContextLinux> m_reg_context_up; - std::string m_stop_description; - using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; - WatchpointIndexMap m_watchpoint_index_map; - WatchpointIndexMap m_hw_break_index_map; - std::unique_ptr<SingleStepWorkaround> m_step_workaround; -}; -} // namespace process_linux -} // namespace lldb_private - -#endif // #ifndef liblldb_NativeThreadLinux_H_ diff --git a/source/Plugins/Process/Linux/ProcessorTrace.cpp b/source/Plugins/Process/Linux/ProcessorTrace.cpp deleted file mode 100644 index 505c526ab70d7..0000000000000 --- a/source/Plugins/Process/Linux/ProcessorTrace.cpp +++ /dev/null @@ -1,395 +0,0 @@ -//===-- ProcessorTrace.cpp ------------------------------------ -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <algorithm> -#include <fstream> - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" - -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "ProcessorTrace.h" -#include "lldb/Host/linux/Support.h" - -#include <sys/syscall.h> - -using namespace lldb; -using namespace lldb_private; -using namespace process_linux; -using namespace llvm; - -lldb::user_id_t ProcessorTraceMonitor::m_trace_num = 1; - -Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - Status error; - - config.setType(lldb::TraceType::eTraceTypeProcessorTrace); - config.setMetaDataBufferSize(m_mmap_meta->data_size); - - config.setTraceBufferSize(m_mmap_meta->aux_size); - - error = GetCPUType(config); - - return error; -#endif -} - -Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid, - const TraceOptions &config) { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - LLDB_LOG(log, "called thread id {0}", tid); - uint64_t page_size = getpagesize(); - uint64_t bufsize = config.getTraceBufferSize(); - uint64_t metabufsize = config.getMetaDataBufferSize(); - - uint64_t numpages = static_cast<uint64_t>( - llvm::PowerOf2Floor((bufsize + page_size - 1) / page_size)); - numpages = std::max<uint64_t>(1, numpages); - bufsize = page_size * numpages; - - numpages = static_cast<uint64_t>( - llvm::PowerOf2Floor((metabufsize + page_size - 1) / page_size)); - metabufsize = page_size * numpages; - - perf_event_attr attr; - memset(&attr, 0, sizeof(attr)); - attr.size = sizeof(attr); - attr.exclude_kernel = 1; - attr.sample_type = PERF_SAMPLE_TIME; - attr.sample_id_all = 1; - attr.exclude_hv = 1; - attr.exclude_idle = 1; - attr.mmap = 1; - - int intel_pt_type = 0; - - auto ret = llvm::MemoryBuffer::getFileAsStream( - "/sys/bus/event_source/devices/intel_pt/type"); - if (!ret) { - LLDB_LOG(log, "failed to open Config file"); - return ret.getError(); - } - - StringRef rest = ret.get()->getBuffer(); - if (rest.empty() || rest.trim().getAsInteger(10, intel_pt_type)) { - LLDB_LOG(log, "failed to read Config file"); - error.SetErrorString("invalid file"); - return error; - } - - rest.trim().getAsInteger(10, intel_pt_type); - LLDB_LOG(log, "intel pt type {0}", intel_pt_type); - attr.type = intel_pt_type; - - LLDB_LOG(log, "meta buffer size {0}", metabufsize); - LLDB_LOG(log, "buffer size {0} ", bufsize); - - if (error.Fail()) { - LLDB_LOG(log, "Status in custom config"); - - return error; - } - - errno = 0; - auto fd = - syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0); - if (fd == -1) { - LLDB_LOG(log, "syscall error {0}", errno); - error.SetErrorString("perf event syscall Failed"); - return error; - } - - m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close()); - - errno = 0; - auto base = - mmap(NULL, (metabufsize + page_size), PROT_WRITE, MAP_SHARED, fd, 0); - - if (base == MAP_FAILED) { - LLDB_LOG(log, "mmap base error {0}", errno); - error.SetErrorString("Meta buffer allocation failed"); - return error; - } - - m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>( - reinterpret_cast<perf_event_mmap_page *>(base), - munmap_delete(metabufsize + page_size)); - - m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size; - m_mmap_meta->aux_size = bufsize; - - errno = 0; - auto mmap_aux = mmap(NULL, bufsize, PROT_READ, MAP_SHARED, fd, - static_cast<long int>(m_mmap_meta->aux_offset)); - - if (mmap_aux == MAP_FAILED) { - LLDB_LOG(log, "second mmap done {0}", errno); - error.SetErrorString("Trace buffer allocation failed"); - return error; - } - m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>( - reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(bufsize)); - return error; -#endif -} - -llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetDataBuffer() { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - return MutableArrayRef<uint8_t>( - (reinterpret_cast<uint8_t *>(m_mmap_meta.get()) + - m_mmap_meta->data_offset), - m_mmap_meta->data_size); -#endif -} - -llvm::MutableArrayRef<uint8_t> ProcessorTraceMonitor::GetAuxBuffer() { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size); -#endif -} - -Status ProcessorTraceMonitor::GetCPUType(TraceOptions &config) { - - Status error; - uint64_t cpu_family = -1; - uint64_t model = -1; - uint64_t stepping = -1; - std::string vendor_id; - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - auto BufferOrError = getProcFile("cpuinfo"); - if (!BufferOrError) - return BufferOrError.getError(); - - LLDB_LOG(log, "GetCPUType Function"); - - StringRef Rest = BufferOrError.get()->getBuffer(); - while (!Rest.empty()) { - StringRef Line; - std::tie(Line, Rest) = Rest.split('\n'); - - SmallVector<StringRef, 2> columns; - Line.split(columns, StringRef(":"), -1, false); - - if (columns.size() < 2) - continue; // continue searching - - columns[1] = columns[1].trim(" "); - if (columns[0].contains("cpu family") && - columns[1].getAsInteger(10, cpu_family)) - continue; - - else if (columns[0].contains("model") && columns[1].getAsInteger(10, model)) - continue; - - else if (columns[0].contains("stepping") && - columns[1].getAsInteger(10, stepping)) - continue; - - else if (columns[0].contains("vendor_id")) { - vendor_id = columns[1].str(); - if (!vendor_id.empty()) - continue; - } - LLDB_LOG(log, "{0}:{1}:{2}:{3}", cpu_family, model, stepping, vendor_id); - - if ((cpu_family != static_cast<uint64_t>(-1)) && - (model != static_cast<uint64_t>(-1)) && - (stepping != static_cast<uint64_t>(-1)) && (!vendor_id.empty())) { - auto params_dict = std::make_shared<StructuredData::Dictionary>(); - params_dict->AddIntegerItem("cpu_family", cpu_family); - params_dict->AddIntegerItem("cpu_model", model); - params_dict->AddIntegerItem("cpu_stepping", stepping); - params_dict->AddStringItem("cpu_vendor", vendor_id); - - llvm::StringRef intel_custom_params_key("intel-pt"); - - auto intel_custom_params = std::make_shared<StructuredData::Dictionary>(); - intel_custom_params->AddItem( - intel_custom_params_key, - StructuredData::ObjectSP(std::move(params_dict))); - - config.setTraceParams(intel_custom_params); - return error; // we are done - } - } - - error.SetErrorString("cpu info not found"); - return error; -} - -llvm::Expected<ProcessorTraceMonitorUP> -ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid, - const TraceOptions &config, - bool useProcessSettings) { - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - Status error; - if (tid == LLDB_INVALID_THREAD_ID) { - error.SetErrorString("thread not specified"); - return error.ToError(); - } - - ProcessorTraceMonitorUP pt_monitor_up(new ProcessorTraceMonitor); - - error = pt_monitor_up->StartTrace(pid, tid, config); - if (error.Fail()) - return error.ToError(); - - pt_monitor_up->SetThreadID(tid); - - if (useProcessSettings) { - pt_monitor_up->SetTraceID(0); - } else { - pt_monitor_up->SetTraceID(m_trace_num++); - LLDB_LOG(log, "Trace ID {0}", m_trace_num); - } - return std::move(pt_monitor_up); -} - -Status -ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset) { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - uint64_t head = m_mmap_meta->aux_head; - - LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head); - - /** - * When configured as ring buffer, the aux buffer keeps wrapping around - * the buffer and its not possible to detect how many times the buffer - * wrapped. Initially the buffer is filled with zeros,as shown below - * so in order to get complete buffer we first copy firstpartsize, followed - * by any left over part from beginning to aux_head - * - * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size - * aux_head->||<- firstpartsize ->| - * - * */ - - ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset); - LLDB_LOG(log, "ReadCyclic BUffer Done"); - return error; -#endif -} - -Status -ProcessorTraceMonitor::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset) { -#ifndef PERF_ATTR_SIZE_VER5 - llvm_unreachable("perf event not supported"); -#else - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - uint64_t bytes_remaining = buffer.size(); - Status error; - - uint64_t head = m_mmap_meta->data_head; - - /* - * The data buffer and aux buffer have different implementations - * with respect to their definition of head pointer. In the case - * of Aux data buffer the head always wraps around the aux buffer - * and we don't need to care about it, whereas the data_head keeps - * increasing and needs to be wrapped by modulus operator - */ - - LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining); - - auto data_buffer = GetDataBuffer(); - - if (head > data_buffer.size()) { - head = head % data_buffer.size(); - LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head); - - ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset); - bytes_remaining -= buffer.size(); - } else { - LLDB_LOG(log, "Head - {0}", head); - if (offset >= head) { - LLDB_LOG(log, "Invalid Offset "); - error.SetErrorString("invalid offset"); - buffer = buffer.slice(buffer.size()); - return error; - } - - auto data = data_buffer.slice(offset, (head - offset)); - auto remaining = std::copy(data.begin(), data.end(), buffer.begin()); - bytes_remaining -= (remaining - buffer.begin()); - } - buffer = buffer.drop_back(bytes_remaining); - return error; -#endif -} - -void ProcessorTraceMonitor::ReadCyclicBuffer( - llvm::MutableArrayRef<uint8_t> &dst, llvm::MutableArrayRef<uint8_t> src, - size_t src_cyc_index, size_t offset) { - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - if (dst.empty() || src.empty()) { - dst = dst.drop_back(dst.size()); - return; - } - - if (dst.data() == nullptr || src.data() == nullptr) { - dst = dst.drop_back(dst.size()); - return; - } - - if (src_cyc_index > src.size()) { - dst = dst.drop_back(dst.size()); - return; - } - - if (offset >= src.size()) { - LLDB_LOG(log, "Too Big offset "); - dst = dst.drop_back(dst.size()); - return; - } - - llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = { - src.slice(src_cyc_index), src.take_front(src_cyc_index)}; - - if (offset > parts[0].size()) { - parts[1] = parts[1].slice(offset - parts[0].size()); - parts[0] = parts[0].drop_back(parts[0].size()); - } else if (offset == parts[0].size()) { - parts[0] = parts[0].drop_back(parts[0].size()); - } else { - parts[0] = parts[0].slice(offset); - } - auto next = dst.begin(); - auto bytes_left = dst.size(); - for (auto part : parts) { - size_t chunk_size = std::min(part.size(), bytes_left); - next = std::copy_n(part.begin(), chunk_size, next); - bytes_left -= chunk_size; - } - dst = dst.drop_back(bytes_left); -} diff --git a/source/Plugins/Process/Linux/ProcessorTrace.h b/source/Plugins/Process/Linux/ProcessorTrace.h deleted file mode 100644 index 6fd918c2bb58a..0000000000000 --- a/source/Plugins/Process/Linux/ProcessorTrace.h +++ /dev/null @@ -1,141 +0,0 @@ -//===-- ProcessorTrace.h -------------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessorTrace_H_ -#define liblldb_ProcessorTrace_H_ - -#include "lldb/Utility/Status.h" -#include "lldb/Utility/TraceOptions.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" - -#include <linux/perf_event.h> -#include <sys/mman.h> -#include <unistd.h> - -namespace lldb_private { - -namespace process_linux { - -// --------------------------------------------------------------------- -// This class keeps track of one tracing instance of -// Intel(R) Processor Trace on Linux OS. There is a map keeping track -// of different tracing instances on each thread, which enables trace -// gathering on a per thread level. -// -// The tracing instance is linked with a trace id. The trace id acts like -// a key to the tracing instance and trace manipulations could be -// performed using the trace id. -// -// The trace id could map to trace instances for a group of threads -// (spanning to all the threads in the process) or a single thread. -// The kernel interface for us is the perf_event_open. -// --------------------------------------------------------------------- - -class ProcessorTraceMonitor; -typedef std::unique_ptr<ProcessorTraceMonitor> ProcessorTraceMonitorUP; - -class ProcessorTraceMonitor { - - class munmap_delete { - size_t m_length; - - public: - munmap_delete(size_t length) : m_length(length) {} - void operator()(void *ptr) { - if (m_length) - munmap(ptr, m_length); - } - }; - - class file_close { - - public: - file_close() = default; - void operator()(int *ptr) { - if (ptr == nullptr) - return; - if (*ptr == -1) - return; - close(*ptr); - std::default_delete<int>()(ptr); - } - }; - - std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta; - std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux; - std::unique_ptr<int, file_close> m_fd; - - // perf_event_mmap_page *m_mmap_base; - lldb::user_id_t m_traceid; - lldb::tid_t m_thread_id; - - // Counter to track trace instances. - static lldb::user_id_t m_trace_num; - - void SetTraceID(lldb::user_id_t traceid) { m_traceid = traceid; } - - Status StartTrace(lldb::pid_t pid, lldb::tid_t tid, - const TraceOptions &config); - - llvm::MutableArrayRef<uint8_t> GetAuxBuffer(); - llvm::MutableArrayRef<uint8_t> GetDataBuffer(); - - ProcessorTraceMonitor() - : m_mmap_meta(nullptr, munmap_delete(0)), - m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()), - m_traceid(LLDB_INVALID_UID), m_thread_id(LLDB_INVALID_THREAD_ID){}; - - void SetThreadID(lldb::tid_t tid) { m_thread_id = tid; } - -public: - static Status GetCPUType(TraceOptions &config); - - static llvm::Expected<ProcessorTraceMonitorUP> - Create(lldb::pid_t pid, lldb::tid_t tid, const TraceOptions &config, - bool useProcessSettings); - - Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset = 0); - - Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer, - size_t offset = 0); - - ~ProcessorTraceMonitor() = default; - - lldb::tid_t GetThreadID() const { return m_thread_id; } - - lldb::user_id_t GetTraceID() const { return m_traceid; } - - Status GetTraceConfig(TraceOptions &config) const; - - // --------------------------------------------------------------------- - /// Read data from a cyclic buffer - /// - /// @param[in] [out] buf - /// Destination buffer, the buffer will be truncated to written size. - /// - /// @param[in] src - /// Source buffer which must be a cyclic buffer. - /// - /// @param[in] src_cyc_index - /// The index pointer (start of the valid data in the cyclic - /// buffer). - /// - /// @param[in] offset - /// The offset to begin reading the data in the cyclic buffer. - // --------------------------------------------------------------------- - static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst, - llvm::MutableArrayRef<uint8_t> src, - size_t src_cyc_index, size_t offset); -}; -} // namespace process_linux -} // namespace lldb_private -#endif diff --git a/source/Plugins/Process/Linux/Procfs.h b/source/Plugins/Process/Linux/Procfs.h deleted file mode 100644 index 1d9c9dbe273fd..0000000000000 --- a/source/Plugins/Process/Linux/Procfs.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- Procfs.h ---------------------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// source/Plugins/Process/Linux/Procfs.h defines the symbols we need from -// sys/procfs.h on Android/Linux for all supported architectures. - -#include <sys/ptrace.h> - -#ifdef __ANDROID__ -#if defined(__arm64__) || defined(__aarch64__) -typedef unsigned long elf_greg_t; -typedef elf_greg_t - elf_gregset_t[(sizeof(struct user_pt_regs) / sizeof(elf_greg_t))]; -typedef struct user_fpsimd_state elf_fpregset_t; -#ifndef NT_FPREGSET -#define NT_FPREGSET NT_PRFPREG -#endif // NT_FPREGSET -#elif defined(__mips__) -#ifndef NT_FPREGSET -#define NT_FPREGSET NT_PRFPREG -#endif // NT_FPREGSET -#endif -#else // __ANDROID__ -#include <sys/procfs.h> -#endif // __ANDROID__ diff --git a/source/Plugins/Process/Linux/SingleStepCheck.cpp b/source/Plugins/Process/Linux/SingleStepCheck.cpp deleted file mode 100644 index c57a2daf22757..0000000000000 --- a/source/Plugins/Process/Linux/SingleStepCheck.cpp +++ /dev/null @@ -1,182 +0,0 @@ -//===-- SingleStepCheck.cpp ----------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SingleStepCheck.h" - -#include <sched.h> -#include <signal.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "NativeProcessLinux.h" - -#include "llvm/Support/Compiler.h" - -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "lldb/Host/linux/Ptrace.h" -#include "lldb/Utility/Status.h" - -using namespace lldb; -using namespace lldb_private; -using namespace lldb_private::process_linux; - -#if defined(__arm64__) || defined(__aarch64__) -namespace { - -void LLVM_ATTRIBUTE_NORETURN Child() { - if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) - _exit(1); - - // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer - // will fiddle with our cpu affinities and monitor the behaviour. - for (;;) { - raise(SIGSTOP); - - // Generate a bunch of instructions here, so that a single-step does not - // land in the raise() accidentally. If single-stepping works, we will be - // spinning in this loop. If it doesn't, we'll land in the raise() call - // above. - for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i) - ; - } -} - -struct ChildDeleter { - ::pid_t pid; - - ~ChildDeleter() { - int status; - kill(pid, SIGKILL); // Kill the child. - waitpid(pid, &status, __WALL); // Pick up the remains. - } -}; - -bool WorkaroundNeeded() { - // We shall spawn a child, and use it to verify the debug capabilities of the - // cpu. We shall iterate through the cpus, bind the child to each one in - // turn, and verify that single-stepping works on that cpu. A workaround is - // needed if we find at least one broken cpu. - - Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - ::pid_t child_pid = fork(); - if (child_pid == -1) { - LLDB_LOG(log, "failed to fork(): {0}", Status(errno, eErrorTypePOSIX)); - return false; - } - if (child_pid == 0) - Child(); - - ChildDeleter child_deleter{child_pid}; - cpu_set_t available_cpus; - if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) == - -1) { - LLDB_LOG(log, "failed to get available cpus: {0}", - Status(errno, eErrorTypePOSIX)); - return false; - } - - int status; - ::pid_t wpid = waitpid(child_pid, &status, __WALL); - if (wpid != child_pid || !WIFSTOPPED(status)) { - LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status, - Status(errno, eErrorTypePOSIX)); - return false; - } - - unsigned cpu; - for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) { - if (!CPU_ISSET(cpu, &available_cpus)) - continue; - - cpu_set_t cpus; - CPU_ZERO(&cpus); - CPU_SET(cpu, &cpus); - if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) { - LLDB_LOG(log, "failed to switch to cpu {0}: {1}", cpu, - Status(errno, eErrorTypePOSIX)); - continue; - } - - int status; - Status error = - NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid); - if (error.Fail()) { - LLDB_LOG(log, "single step failed: {0}", error); - break; - } - - wpid = waitpid(child_pid, &status, __WALL); - if (wpid != child_pid || !WIFSTOPPED(status)) { - LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status, - Status(errno, eErrorTypePOSIX)); - break; - } - if (WSTOPSIG(status) != SIGTRAP) { - LLDB_LOG(log, "single stepping on cpu {0} failed with status {1:x}", cpu, - status); - break; - } - } - - // cpu is either the index of the first broken cpu, or CPU_SETSIZE. - if (cpu == 0) { - LLDB_LOG(log, - "SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING " - "LIKELY TO BE UNRELIABLE."); - // No point in trying to fiddle with the affinities, just give it our best - // shot and see how it goes. - return false; - } - - return cpu != CPU_SETSIZE; -} - -} // end anonymous namespace - -std::unique_ptr<SingleStepWorkaround> SingleStepWorkaround::Get(::pid_t tid) { - Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - - static bool workaround_needed = WorkaroundNeeded(); - if (!workaround_needed) { - LLDB_LOG(log, "workaround for thread {0} not needed", tid); - return nullptr; - } - - cpu_set_t original_set; - if (sched_getaffinity(tid, sizeof original_set, &original_set) != 0) { - // This should really not fail. But, just in case... - LLDB_LOG(log, "Unable to get cpu affinity for thread {0}: {1}", tid, - Status(errno, eErrorTypePOSIX)); - return nullptr; - } - - cpu_set_t set; - CPU_ZERO(&set); - CPU_SET(0, &set); - if (sched_setaffinity(tid, sizeof set, &set) != 0) { - // This may fail in very locked down systems, if the thread is not allowed - // to run on cpu 0. If that happens, only thing we can do is it log it and - // continue... - LLDB_LOG(log, "Unable to set cpu affinity for thread {0}: {1}", tid, - Status(errno, eErrorTypePOSIX)); - } - - LLDB_LOG(log, "workaround for thread {0} prepared", tid); - return llvm::make_unique<SingleStepWorkaround>(tid, original_set); -} - -SingleStepWorkaround::~SingleStepWorkaround() { - Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); - LLDB_LOG(log, "Removing workaround"); - if (sched_setaffinity(m_tid, sizeof m_original_set, &m_original_set) != 0) { - LLDB_LOG(log, "Unable to reset cpu affinity for thread {0}: {1}", m_tid, - Status(errno, eErrorTypePOSIX)); - } -} -#endif diff --git a/source/Plugins/Process/Linux/SingleStepCheck.h b/source/Plugins/Process/Linux/SingleStepCheck.h deleted file mode 100644 index afeda7310349a..0000000000000 --- a/source/Plugins/Process/Linux/SingleStepCheck.h +++ /dev/null @@ -1,57 +0,0 @@ -//===-- SingleStepCheck.h ------------------------------------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_SingleStepCheck_H_ -#define liblldb_SingleStepCheck_H_ - -#include <memory> -#include <sched.h> -#include <sys/types.h> - -namespace lldb_private { -namespace process_linux { - -// arm64 linux had a bug which prevented single-stepping and watchpoints from -// working on non-boot cpus, due to them being incorrectly initialized after -// coming out of suspend. This issue is particularly affecting android M, which -// uses suspend ("doze mode") quite aggressively. This code detects that -// situation and makes single-stepping work by doing all the step operations on -// the boot cpu. -// -// The underlying issue has been fixed in android N and linux 4.4. This code can -// be removed once these systems become obsolete. - -#if defined(__arm64__) || defined(__aarch64__) -class SingleStepWorkaround { - ::pid_t m_tid; - cpu_set_t m_original_set; - - SingleStepWorkaround(const SingleStepWorkaround &) = delete; - void operator=(const SingleStepWorkaround &) = delete; - -public: - SingleStepWorkaround(::pid_t tid, cpu_set_t original_set) - : m_tid(tid), m_original_set(original_set) {} - ~SingleStepWorkaround(); - - static std::unique_ptr<SingleStepWorkaround> Get(::pid_t tid); -}; -#else -class SingleStepWorkaround { -public: - static std::unique_ptr<SingleStepWorkaround> Get(::pid_t tid) { - return nullptr; - } -}; -#endif - -} // end namespace process_linux -} // end namespace lldb_private - -#endif // #ifndef liblldb_SingleStepCheck_H_ diff --git a/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt deleted file mode 100644 index bed0e3b7ab377..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -add_lldb_library(lldbPluginProcessMacOSXKernel PLUGIN - CommunicationKDP.cpp - ProcessKDP.cpp - ProcessKDPLog.cpp - RegisterContextKDP_arm.cpp - RegisterContextKDP_arm64.cpp - RegisterContextKDP_i386.cpp - RegisterContextKDP_x86_64.cpp - ThreadKDP.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbHost - lldbInterpreter - lldbSymbol - lldbTarget - lldbUtility - lldbPluginDynamicLoaderDarwinKernel - lldbPluginDynamicLoaderStatic - lldbPluginProcessUtility - ) diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp deleted file mode 100644 index 8908108eff4bd..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ /dev/null @@ -1,1289 +0,0 @@ -//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "CommunicationKDP.h" - -#include <errno.h> -#include <limits.h> -#include <string.h> - - -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Host/Host.h" -#include "lldb/Target/Process.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/UUID.h" - -#include "ProcessKDPLog.h" - -using namespace lldb; -using namespace lldb_private; - -//---------------------------------------------------------------------- -// CommunicationKDP constructor -//---------------------------------------------------------------------- -CommunicationKDP::CommunicationKDP(const char *comm_name) - : Communication(comm_name), m_addr_byte_size(4), - m_byte_order(eByteOrderLittle), m_packet_timeout(5), m_sequence_mutex(), - m_is_running(false), m_session_key(0u), m_request_sequence_id(0u), - m_exception_sequence_id(0u), m_kdp_version_version(0u), - m_kdp_version_feature(0u), m_kdp_hostinfo_cpu_mask(0u), - m_kdp_hostinfo_cpu_type(0u), m_kdp_hostinfo_cpu_subtype(0u) {} - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -CommunicationKDP::~CommunicationKDP() { - if (IsConnected()) { - Disconnect(); - } -} - -bool CommunicationKDP::SendRequestPacket( - const PacketStreamType &request_packet) { - std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex); - return SendRequestPacketNoLock(request_packet); -} - -void CommunicationKDP::MakeRequestPacketHeader(CommandType request_type, - PacketStreamType &request_packet, - uint16_t request_length) { - request_packet.Clear(); - request_packet.PutHex8(request_type | - ePacketTypeRequest); // Set the request type - request_packet.PutHex8(m_request_sequence_id++); // Sequence number - request_packet.PutHex16( - request_length); // Length of the packet including this header - request_packet.PutHex32(m_session_key); // Session key -} - -bool CommunicationKDP::SendRequestAndGetReply( - const CommandType command, const PacketStreamType &request_packet, - DataExtractor &reply_packet) { - if (IsRunning()) { - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PACKETS)); - if (log) { - PacketStreamType log_strm; - DumpPacket(log_strm, request_packet.GetData(), request_packet.GetSize()); - log->Printf("error: kdp running, not sending packet: %.*s", - (uint32_t)log_strm.GetSize(), log_strm.GetData()); - } - return false; - } - - std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex); -#ifdef LLDB_CONFIGURATION_DEBUG - // NOTE: this only works for packets that are in native endian byte order - assert(request_packet.GetSize() == - *((const uint16_t *)(request_packet.GetData() + 2))); -#endif - lldb::offset_t offset = 1; - const uint32_t num_retries = 3; - for (uint32_t i = 0; i < num_retries; ++i) { - if (SendRequestPacketNoLock(request_packet)) { - const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1]; - while (1) { - if (WaitForPacketWithTimeoutMicroSecondsNoLock( - reply_packet, - std::chrono::microseconds(GetPacketTimeout()).count())) { - offset = 0; - const uint8_t reply_command = reply_packet.GetU8(&offset); - const uint8_t reply_sequence_id = reply_packet.GetU8(&offset); - if (request_sequence_id == reply_sequence_id) { - // The sequent ID was correct, now verify we got the response we - // were looking for - if ((reply_command & eCommandTypeMask) == command) { - // Success - if (command == KDP_RESUMECPUS) - m_is_running.SetValue(true, eBroadcastAlways); - return true; - } else { - // Failed to get the correct response, bail - reply_packet.Clear(); - return false; - } - } else if (reply_sequence_id > request_sequence_id) { - // Sequence ID was greater than the sequence ID of the packet we - // sent, something is really wrong... - reply_packet.Clear(); - return false; - } else { - // The reply sequence ID was less than our current packet's - // sequence ID so we should keep trying to get a response because - // this was a response for a previous packet that we must have - // retried. - } - } else { - // Break and retry sending the packet as we didn't get a response due - // to timeout - break; - } - } - } - } - reply_packet.Clear(); - return false; -} - -bool CommunicationKDP::SendRequestPacketNoLock( - const PacketStreamType &request_packet) { - if (IsConnected()) { - const char *packet_data = request_packet.GetData(); - const size_t packet_size = request_packet.GetSize(); - - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PACKETS)); - if (log) { - PacketStreamType log_strm; - DumpPacket(log_strm, packet_data, packet_size); - log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); - } - ConnectionStatus status = eConnectionStatusSuccess; - - size_t bytes_written = Write(packet_data, packet_size, status, NULL); - - if (bytes_written == packet_size) - return true; - - if (log) - log->Printf("error: failed to send packet entire packet %" PRIu64 - " of %" PRIu64 " bytes sent", - (uint64_t)bytes_written, (uint64_t)packet_size); - } - return false; -} - -bool CommunicationKDP::GetSequenceMutex( - std::unique_lock<std::recursive_mutex> &lock) { - return (lock = std::unique_lock<std::recursive_mutex>(m_sequence_mutex, - std::try_to_lock)) - .owns_lock(); -} - -bool CommunicationKDP::WaitForNotRunningPrivate( - const std::chrono::microseconds &timeout) { - return m_is_running.WaitForValueEqualTo(false, timeout); -} - -size_t -CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds(DataExtractor &packet, - uint32_t timeout_usec) { - std::lock_guard<std::recursive_mutex> guard(m_sequence_mutex); - return WaitForPacketWithTimeoutMicroSecondsNoLock(packet, timeout_usec); -} - -size_t CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock( - DataExtractor &packet, uint32_t timeout_usec) { - uint8_t buffer[8192]; - Status error; - - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PACKETS)); - - // Check for a packet from our cache first without trying any reading... - if (CheckForPacket(NULL, 0, packet)) - return packet.GetByteSize(); - - bool timed_out = false; - while (IsConnected() && !timed_out) { - lldb::ConnectionStatus status = eConnectionStatusNoConnection; - size_t bytes_read = Read(buffer, sizeof(buffer), - timeout_usec == UINT32_MAX - ? Timeout<std::micro>(llvm::None) - : std::chrono::microseconds(timeout_usec), - status, &error); - - LLDB_LOGV(log, - "Read (buffer, sizeof(buffer), timeout_usec = 0x{0:x}, " - "status = {1}, error = {2}) => bytes_read = {4}", - timeout_usec, - Communication::ConnectionStatusAsCString(status), - error, bytes_read); - - if (bytes_read > 0) { - if (CheckForPacket(buffer, bytes_read, packet)) - return packet.GetByteSize(); - } else { - switch (status) { - case eConnectionStatusInterrupted: - case eConnectionStatusTimedOut: - timed_out = true; - break; - case eConnectionStatusSuccess: - // printf ("status = success but error = %s\n", - // error.AsCString("<invalid>")); - break; - - case eConnectionStatusEndOfFile: - case eConnectionStatusNoConnection: - case eConnectionStatusLostConnection: - case eConnectionStatusError: - Disconnect(); - break; - } - } - } - packet.Clear(); - return 0; -} - -bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len, - DataExtractor &packet) { - // Put the packet data into the buffer in a thread safe fashion - std::lock_guard<std::recursive_mutex> guard(m_bytes_mutex); - - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PACKETS)); - - if (src && src_len > 0) { - if (log && log->GetVerbose()) { - PacketStreamType log_strm; - DumpHexBytes(&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS); - log->Printf("CommunicationKDP::%s adding %u bytes: %s", __FUNCTION__, - (uint32_t)src_len, log_strm.GetData()); - } - m_bytes.append((const char *)src, src_len); - } - - // Make sure we at least have enough bytes for a packet header - const size_t bytes_available = m_bytes.size(); - if (bytes_available >= 8) { - packet.SetData(&m_bytes[0], bytes_available, m_byte_order); - lldb::offset_t offset = 0; - uint8_t reply_command = packet.GetU8(&offset); - switch (reply_command) { - case ePacketTypeRequest | KDP_EXCEPTION: - case ePacketTypeRequest | KDP_TERMINATION: - // We got an exception request, so be sure to send an ACK - { - PacketStreamType request_ack_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - // Set the reply but and make the ACK packet - request_ack_packet.PutHex8(reply_command | ePacketTypeReply); - request_ack_packet.PutHex8(packet.GetU8(&offset)); - request_ack_packet.PutHex16(packet.GetU16(&offset)); - request_ack_packet.PutHex32(packet.GetU32(&offset)); - m_is_running.SetValue(false, eBroadcastAlways); - // Ack to the exception or termination - SendRequestPacketNoLock(request_ack_packet); - } - // Fall through to case below to get packet contents - LLVM_FALLTHROUGH; - case ePacketTypeReply | KDP_CONNECT: - case ePacketTypeReply | KDP_DISCONNECT: - case ePacketTypeReply | KDP_HOSTINFO: - case ePacketTypeReply | KDP_VERSION: - case ePacketTypeReply | KDP_MAXBYTES: - case ePacketTypeReply | KDP_READMEM: - case ePacketTypeReply | KDP_WRITEMEM: - case ePacketTypeReply | KDP_READREGS: - case ePacketTypeReply | KDP_WRITEREGS: - case ePacketTypeReply | KDP_LOAD: - case ePacketTypeReply | KDP_IMAGEPATH: - case ePacketTypeReply | KDP_SUSPEND: - case ePacketTypeReply | KDP_RESUMECPUS: - case ePacketTypeReply | KDP_BREAKPOINT_SET: - case ePacketTypeReply | KDP_BREAKPOINT_REMOVE: - case ePacketTypeReply | KDP_REGIONS: - case ePacketTypeReply | KDP_REATTACH: - case ePacketTypeReply | KDP_HOSTREBOOT: - case ePacketTypeReply | KDP_READMEM64: - case ePacketTypeReply | KDP_WRITEMEM64: - case ePacketTypeReply | KDP_BREAKPOINT_SET64: - case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64: - case ePacketTypeReply | KDP_KERNELVERSION: - case ePacketTypeReply | KDP_READPHYSMEM64: - case ePacketTypeReply | KDP_WRITEPHYSMEM64: - case ePacketTypeReply | KDP_READIOPORT: - case ePacketTypeReply | KDP_WRITEIOPORT: - case ePacketTypeReply | KDP_READMSR64: - case ePacketTypeReply | KDP_WRITEMSR64: - case ePacketTypeReply | KDP_DUMPINFO: { - offset = 2; - const uint16_t length = packet.GetU16(&offset); - if (length <= bytes_available) { - // We have an entire packet ready, we need to copy the data bytes into - // a buffer that will be owned by the packet and erase the bytes from - // our communcation buffer "m_bytes" - packet.SetData(DataBufferSP(new DataBufferHeap(&m_bytes[0], length))); - m_bytes.erase(0, length); - - if (log) { - PacketStreamType log_strm; - DumpPacket(log_strm, packet); - - log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); - } - return true; - } - } break; - - default: - // Unrecognized reply command byte, erase this byte and try to get back - // on track - if (log) - log->Printf("CommunicationKDP::%s: tossing junk byte: 0x%2.2x", - __FUNCTION__, (uint8_t)m_bytes[0]); - m_bytes.erase(0, 1); - break; - } - } - packet.Clear(); - return false; -} - -bool CommunicationKDP::SendRequestConnect(uint16_t reply_port, - uint16_t exc_port, - const char *greeting) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - if (greeting == NULL) - greeting = ""; - - const CommandType command = KDP_CONNECT; - // Length is 82 uint16_t and the length of the greeting C string with the - // terminating NULL - const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1; - MakeRequestPacketHeader(command, request_packet, command_length); - // Always send connect ports as little endian - request_packet.SetByteOrder(eByteOrderLittle); - request_packet.PutHex16(htons(reply_port)); - request_packet.PutHex16(htons(exc_port)); - request_packet.SetByteOrder(m_byte_order); - request_packet.PutCString(greeting); - DataExtractor reply_packet; - return SendRequestAndGetReply(command, request_packet, reply_packet); -} - -void CommunicationKDP::ClearKDPSettings() { - m_request_sequence_id = 0; - m_kdp_version_version = 0; - m_kdp_version_feature = 0; - m_kdp_hostinfo_cpu_mask = 0; - m_kdp_hostinfo_cpu_type = 0; - m_kdp_hostinfo_cpu_subtype = 0; -} - -bool CommunicationKDP::SendRequestReattach(uint16_t reply_port) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_REATTACH; - // Length is 8 bytes for the header plus 2 bytes for the reply UDP port - const uint32_t command_length = 8 + 2; - MakeRequestPacketHeader(command, request_packet, command_length); - // Always send connect ports as little endian - request_packet.SetByteOrder(eByteOrderLittle); - request_packet.PutHex16(htons(reply_port)); - request_packet.SetByteOrder(m_byte_order); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - // Reset the sequence ID to zero for reattach - ClearKDPSettings(); - lldb::offset_t offset = 4; - m_session_key = reply_packet.GetU32(&offset); - return true; - } - return false; -} - -uint32_t CommunicationKDP::GetVersion() { - if (!VersionIsValid()) - SendRequestVersion(); - return m_kdp_version_version; -} - -uint32_t CommunicationKDP::GetFeatureFlags() { - if (!VersionIsValid()) - SendRequestVersion(); - return m_kdp_version_feature; -} - -bool CommunicationKDP::SendRequestVersion() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_VERSION; - const uint32_t command_length = 8; - MakeRequestPacketHeader(command, request_packet, command_length); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - m_kdp_version_version = reply_packet.GetU32(&offset); - m_kdp_version_feature = reply_packet.GetU32(&offset); - return true; - } - return false; -} - -uint32_t CommunicationKDP::GetCPUMask() { - if (!HostInfoIsValid()) - SendRequestHostInfo(); - return m_kdp_hostinfo_cpu_mask; -} - -uint32_t CommunicationKDP::GetCPUType() { - if (!HostInfoIsValid()) - SendRequestHostInfo(); - return m_kdp_hostinfo_cpu_type; -} - -uint32_t CommunicationKDP::GetCPUSubtype() { - if (!HostInfoIsValid()) - SendRequestHostInfo(); - return m_kdp_hostinfo_cpu_subtype; -} - -lldb_private::UUID CommunicationKDP::GetUUID() { - UUID uuid; - if (GetKernelVersion() == NULL) - return uuid; - - if (m_kernel_version.find("UUID=") == std::string::npos) - return uuid; - - size_t p = m_kernel_version.find("UUID=") + strlen("UUID="); - std::string uuid_str = m_kernel_version.substr(p, 36); - if (uuid_str.size() < 32) - return uuid; - - if (uuid.SetFromStringRef(uuid_str) == 0) { - UUID invalid_uuid; - return invalid_uuid; - } - - return uuid; -} - -bool CommunicationKDP::RemoteIsEFI() { - if (GetKernelVersion() == NULL) - return false; - return strncmp(m_kernel_version.c_str(), "EFI", 3) == 0; -} - -bool CommunicationKDP::RemoteIsDarwinKernel() { - if (GetKernelVersion() == NULL) - return false; - return m_kernel_version.find("Darwin Kernel") != std::string::npos; -} - -lldb::addr_t CommunicationKDP::GetLoadAddress() { - if (GetKernelVersion() == NULL) - return LLDB_INVALID_ADDRESS; - - if (m_kernel_version.find("stext=") == std::string::npos) - return LLDB_INVALID_ADDRESS; - size_t p = m_kernel_version.find("stext=") + strlen("stext="); - if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x') - return LLDB_INVALID_ADDRESS; - - addr_t kernel_load_address; - errno = 0; - kernel_load_address = ::strtoul(m_kernel_version.c_str() + p, NULL, 16); - if (errno != 0 || kernel_load_address == 0) - return LLDB_INVALID_ADDRESS; - - return kernel_load_address; -} - -bool CommunicationKDP::SendRequestHostInfo() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_HOSTINFO; - const uint32_t command_length = 8; - MakeRequestPacketHeader(command, request_packet, command_length); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - m_kdp_hostinfo_cpu_mask = reply_packet.GetU32(&offset); - m_kdp_hostinfo_cpu_type = reply_packet.GetU32(&offset); - m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32(&offset); - - ArchSpec kernel_arch; - kernel_arch.SetArchitecture(eArchTypeMachO, m_kdp_hostinfo_cpu_type, - m_kdp_hostinfo_cpu_subtype); - - m_addr_byte_size = kernel_arch.GetAddressByteSize(); - m_byte_order = kernel_arch.GetByteOrder(); - return true; - } - return false; -} - -const char *CommunicationKDP::GetKernelVersion() { - if (m_kernel_version.empty()) - SendRequestKernelVersion(); - return m_kernel_version.c_str(); -} - -bool CommunicationKDP::SendRequestKernelVersion() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_KERNELVERSION; - const uint32_t command_length = 8; - MakeRequestPacketHeader(command, request_packet, command_length); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - const char *kernel_version_cstr = reply_packet.PeekCStr(8); - if (kernel_version_cstr && kernel_version_cstr[0]) - m_kernel_version.assign(kernel_version_cstr); - return true; - } - return false; -} - -bool CommunicationKDP::SendRequestDisconnect() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_DISCONNECT; - const uint32_t command_length = 8; - MakeRequestPacketHeader(command, request_packet, command_length); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - // Are we supposed to get a reply for disconnect? - } - ClearKDPSettings(); - return true; -} - -uint32_t CommunicationKDP::SendRequestReadMemory(lldb::addr_t addr, void *dst, - uint32_t dst_len, - Status &error) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - bool use_64 = (GetVersion() >= 11); - uint32_t command_addr_byte_size = use_64 ? 8 : 4; - const CommandType command = use_64 ? KDP_READMEM64 : KDP_READMEM; - // Size is header + address size + uint32_t length - const uint32_t command_length = 8 + command_addr_byte_size + 4; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutMaxHex64(addr, command_addr_byte_size); - request_packet.PutHex32(dst_len); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - uint32_t src_len = reply_packet.GetByteSize() - 12; - - if (src_len > 0) { - const void *src = reply_packet.GetData(&offset, src_len); - if (src) { - ::memcpy(dst, src, src_len); - error.Clear(); - return src_len; - } - } - if (kdp_error) - error.SetErrorStringWithFormat("kdp read memory failed (error %u)", - kdp_error); - else - error.SetErrorString("kdp read memory failed"); - } else { - error.SetErrorString("failed to send packet"); - } - return 0; -} - -uint32_t CommunicationKDP::SendRequestWriteMemory(lldb::addr_t addr, - const void *src, - uint32_t src_len, - Status &error) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - bool use_64 = (GetVersion() >= 11); - uint32_t command_addr_byte_size = use_64 ? 8 : 4; - const CommandType command = use_64 ? KDP_WRITEMEM64 : KDP_WRITEMEM; - // Size is header + address size + uint32_t length - const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutMaxHex64(addr, command_addr_byte_size); - request_packet.PutHex32(src_len); - request_packet.PutRawBytes(src, src_len); - - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - if (kdp_error) - error.SetErrorStringWithFormat("kdp write memory failed (error %u)", - kdp_error); - else { - error.Clear(); - return src_len; - } - } else { - error.SetErrorString("failed to send packet"); - } - return 0; -} - -bool CommunicationKDP::SendRawRequest( - uint8_t command_byte, - const void *src, // Raw packet payload bytes - uint32_t src_len, // Raw packet payload length - DataExtractor &reply_packet, Status &error) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - // Size is header + address size + uint32_t length - const uint32_t command_length = 8 + src_len; - const CommandType command = (CommandType)command_byte; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutRawBytes(src, src_len); - - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - if (kdp_error && (command_byte != KDP_DUMPINFO)) - error.SetErrorStringWithFormat("request packet 0x%8.8x failed (error %u)", - command_byte, kdp_error); - else { - error.Clear(); - return true; - } - } else { - error.SetErrorString("failed to send packet"); - } - return false; -} - -const char *CommunicationKDP::GetCommandAsCString(uint8_t command) { - switch (command) { - case KDP_CONNECT: - return "KDP_CONNECT"; - case KDP_DISCONNECT: - return "KDP_DISCONNECT"; - case KDP_HOSTINFO: - return "KDP_HOSTINFO"; - case KDP_VERSION: - return "KDP_VERSION"; - case KDP_MAXBYTES: - return "KDP_MAXBYTES"; - case KDP_READMEM: - return "KDP_READMEM"; - case KDP_WRITEMEM: - return "KDP_WRITEMEM"; - case KDP_READREGS: - return "KDP_READREGS"; - case KDP_WRITEREGS: - return "KDP_WRITEREGS"; - case KDP_LOAD: - return "KDP_LOAD"; - case KDP_IMAGEPATH: - return "KDP_IMAGEPATH"; - case KDP_SUSPEND: - return "KDP_SUSPEND"; - case KDP_RESUMECPUS: - return "KDP_RESUMECPUS"; - case KDP_EXCEPTION: - return "KDP_EXCEPTION"; - case KDP_TERMINATION: - return "KDP_TERMINATION"; - case KDP_BREAKPOINT_SET: - return "KDP_BREAKPOINT_SET"; - case KDP_BREAKPOINT_REMOVE: - return "KDP_BREAKPOINT_REMOVE"; - case KDP_REGIONS: - return "KDP_REGIONS"; - case KDP_REATTACH: - return "KDP_REATTACH"; - case KDP_HOSTREBOOT: - return "KDP_HOSTREBOOT"; - case KDP_READMEM64: - return "KDP_READMEM64"; - case KDP_WRITEMEM64: - return "KDP_WRITEMEM64"; - case KDP_BREAKPOINT_SET64: - return "KDP_BREAKPOINT64_SET"; - case KDP_BREAKPOINT_REMOVE64: - return "KDP_BREAKPOINT64_REMOVE"; - case KDP_KERNELVERSION: - return "KDP_KERNELVERSION"; - case KDP_READPHYSMEM64: - return "KDP_READPHYSMEM64"; - case KDP_WRITEPHYSMEM64: - return "KDP_WRITEPHYSMEM64"; - case KDP_READIOPORT: - return "KDP_READIOPORT"; - case KDP_WRITEIOPORT: - return "KDP_WRITEIOPORT"; - case KDP_READMSR64: - return "KDP_READMSR64"; - case KDP_WRITEMSR64: - return "KDP_WRITEMSR64"; - case KDP_DUMPINFO: - return "KDP_DUMPINFO"; - } - return NULL; -} - -void CommunicationKDP::DumpPacket(Stream &s, const void *data, - uint32_t data_len) { - DataExtractor extractor(data, data_len, m_byte_order, m_addr_byte_size); - DumpPacket(s, extractor); -} - -void CommunicationKDP::DumpPacket(Stream &s, const DataExtractor &packet) { - const char *error_desc = NULL; - if (packet.GetByteSize() < 8) { - error_desc = "error: invalid packet (too short): "; - } else { - lldb::offset_t offset = 0; - const uint8_t first_packet_byte = packet.GetU8(&offset); - const uint8_t sequence_id = packet.GetU8(&offset); - const uint16_t length = packet.GetU16(&offset); - const uint32_t key = packet.GetU32(&offset); - const CommandType command = ExtractCommand(first_packet_byte); - const char *command_name = GetCommandAsCString(command); - if (command_name) { - const bool is_reply = ExtractIsReply(first_packet_byte); - s.Printf("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ", - IsRunning(), is_reply ? "<--" : "-->", command_name, - first_packet_byte, sequence_id, length, key); - - if (is_reply) { - // Dump request reply packets - switch (command) { - // Commands that return a single 32 bit error - case KDP_CONNECT: - case KDP_WRITEMEM: - case KDP_WRITEMEM64: - case KDP_BREAKPOINT_SET: - case KDP_BREAKPOINT_REMOVE: - case KDP_BREAKPOINT_SET64: - case KDP_BREAKPOINT_REMOVE64: - case KDP_WRITEREGS: - case KDP_LOAD: - case KDP_WRITEIOPORT: - case KDP_WRITEMSR64: { - const uint32_t error = packet.GetU32(&offset); - s.Printf(" (error=0x%8.8x)", error); - } break; - - case KDP_DISCONNECT: - case KDP_REATTACH: - case KDP_HOSTREBOOT: - case KDP_SUSPEND: - case KDP_RESUMECPUS: - case KDP_EXCEPTION: - case KDP_TERMINATION: - // No return value for the reply, just the header to ack - s.PutCString(" ()"); - break; - - case KDP_HOSTINFO: { - const uint32_t cpu_mask = packet.GetU32(&offset); - const uint32_t cpu_type = packet.GetU32(&offset); - const uint32_t cpu_subtype = packet.GetU32(&offset); - s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)", - cpu_mask, cpu_type, cpu_subtype); - } break; - - case KDP_VERSION: { - const uint32_t version = packet.GetU32(&offset); - const uint32_t feature = packet.GetU32(&offset); - s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature); - } break; - - case KDP_REGIONS: { - const uint32_t region_count = packet.GetU32(&offset); - s.Printf(" (count = %u", region_count); - for (uint32_t i = 0; i < region_count; ++i) { - const addr_t region_addr = packet.GetPointer(&offset); - const uint32_t region_size = packet.GetU32(&offset); - const uint32_t region_prot = packet.GetU32(&offset); - s.Printf("\n\tregion[%" PRIu64 "] = { range = [0x%16.16" PRIx64 - " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }", - region_addr, region_addr, region_addr + region_size, - region_size, GetPermissionsAsCString(region_prot)); - } - } break; - - case KDP_READMEM: - case KDP_READMEM64: - case KDP_READPHYSMEM64: { - const uint32_t error = packet.GetU32(&offset); - const uint32_t count = packet.GetByteSize() - offset; - s.Printf(" (error = 0x%8.8x:\n", error); - if (count > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatBytesWithASCII, // Format to use - 1, // Size of each item - // in bytes - count, // Number of items - 16, // Number per line - m_last_read_memory_addr, // Don't show addresses - // before each line - 0, 0); // No bitfields - } break; - - case KDP_READREGS: { - const uint32_t error = packet.GetU32(&offset); - const uint32_t count = packet.GetByteSize() - offset; - s.Printf(" (error = 0x%8.8x regs:\n", error); - if (count > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - m_addr_byte_size, // Size of each item - // in bytes - count / m_addr_byte_size, // Number of items - 16 / m_addr_byte_size, // Number per line - LLDB_INVALID_ADDRESS, - // Don't - // show addresses before - // each line - 0, 0); // No bitfields - } break; - - case KDP_KERNELVERSION: { - const char *kernel_version = packet.PeekCStr(8); - s.Printf(" (version = \"%s\")", kernel_version); - } break; - - case KDP_MAXBYTES: { - const uint32_t max_bytes = packet.GetU32(&offset); - s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes); - } break; - case KDP_IMAGEPATH: { - const char *path = packet.GetCStr(&offset); - s.Printf(" (path = \"%s\")", path); - } break; - - case KDP_READIOPORT: - case KDP_READMSR64: { - const uint32_t error = packet.GetU32(&offset); - const uint32_t count = packet.GetByteSize() - offset; - s.Printf(" (error = 0x%8.8x io:\n", error); - if (count > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - 1, // Size of each item in bytes - count, // Number of items - 16, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses - // before each line - 0, 0); // No bitfields - } break; - case KDP_DUMPINFO: { - const uint32_t count = packet.GetByteSize() - offset; - s.Printf(" (count = %u, bytes = \n", count); - if (count > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - 1, // Size of each item in - // bytes - count, // Number of items - 16, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses - // before each line - 0, 0); // No bitfields - - } break; - - default: - s.Printf(" (add support for dumping this packet reply!!!"); - break; - } - } else { - // Dump request packets - switch (command) { - case KDP_CONNECT: { - const uint16_t reply_port = ntohs(packet.GetU16(&offset)); - const uint16_t exc_port = ntohs(packet.GetU16(&offset)); - s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")", - reply_port, exc_port, packet.GetCStr(&offset)); - } break; - - case KDP_DISCONNECT: - case KDP_HOSTREBOOT: - case KDP_HOSTINFO: - case KDP_VERSION: - case KDP_REGIONS: - case KDP_KERNELVERSION: - case KDP_MAXBYTES: - case KDP_IMAGEPATH: - case KDP_SUSPEND: - // No args, just the header in the request... - s.PutCString(" ()"); - break; - - case KDP_RESUMECPUS: { - const uint32_t cpu_mask = packet.GetU32(&offset); - s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask); - } break; - - case KDP_READMEM: { - const uint32_t addr = packet.GetU32(&offset); - const uint32_t size = packet.GetU32(&offset); - s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size); - m_last_read_memory_addr = addr; - } break; - - case KDP_WRITEMEM: { - const uint32_t addr = packet.GetU32(&offset); - const uint32_t size = packet.GetU32(&offset); - s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size); - if (size > 0) - DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); - } break; - - case KDP_READMEM64: { - const uint64_t addr = packet.GetU64(&offset); - const uint32_t size = packet.GetU32(&offset); - s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size); - m_last_read_memory_addr = addr; - } break; - - case KDP_READPHYSMEM64: { - const uint64_t addr = packet.GetU64(&offset); - const uint32_t size = packet.GetU32(&offset); - const uint32_t lcpu = packet.GetU16(&offset); - s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size, - lcpu); - m_last_read_memory_addr = addr; - } break; - - case KDP_WRITEMEM64: { - const uint64_t addr = packet.GetU64(&offset); - const uint32_t size = packet.GetU32(&offset); - s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr, - size); - if (size > 0) - DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); - } break; - - case KDP_WRITEPHYSMEM64: { - const uint64_t addr = packet.GetU64(&offset); - const uint32_t size = packet.GetU32(&offset); - const uint32_t lcpu = packet.GetU16(&offset); - s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n", - addr, size, lcpu); - if (size > 0) - DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); - } break; - - case KDP_READREGS: { - const uint32_t cpu = packet.GetU32(&offset); - const uint32_t flavor = packet.GetU32(&offset); - s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor); - } break; - - case KDP_WRITEREGS: { - const uint32_t cpu = packet.GetU32(&offset); - const uint32_t flavor = packet.GetU32(&offset); - const uint32_t nbytes = packet.GetByteSize() - offset; - s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor); - if (nbytes > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within - // "packet" - eFormatHex, // Format to use - m_addr_byte_size, // Size of each item in - // bytes - nbytes / m_addr_byte_size, // Number of items - 16 / m_addr_byte_size, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses - // before each line - 0, 0); // No bitfields - } break; - - case KDP_BREAKPOINT_SET: - case KDP_BREAKPOINT_REMOVE: { - const uint32_t addr = packet.GetU32(&offset); - s.Printf(" (addr = 0x%8.8x)", addr); - } break; - - case KDP_BREAKPOINT_SET64: - case KDP_BREAKPOINT_REMOVE64: { - const uint64_t addr = packet.GetU64(&offset); - s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr); - } break; - - case KDP_LOAD: { - const char *path = packet.GetCStr(&offset); - s.Printf(" (path = \"%s\")", path); - } break; - - case KDP_EXCEPTION: { - const uint32_t count = packet.GetU32(&offset); - - for (uint32_t i = 0; i < count; ++i) { - const uint32_t cpu = packet.GetU32(&offset); - const uint32_t exc = packet.GetU32(&offset); - const uint32_t code = packet.GetU32(&offset); - const uint32_t subcode = packet.GetU32(&offset); - const char *exc_cstr = NULL; - switch (exc) { - case 1: - exc_cstr = "EXC_BAD_ACCESS"; - break; - case 2: - exc_cstr = "EXC_BAD_INSTRUCTION"; - break; - case 3: - exc_cstr = "EXC_ARITHMETIC"; - break; - case 4: - exc_cstr = "EXC_EMULATION"; - break; - case 5: - exc_cstr = "EXC_SOFTWARE"; - break; - case 6: - exc_cstr = "EXC_BREAKPOINT"; - break; - case 7: - exc_cstr = "EXC_SYSCALL"; - break; - case 8: - exc_cstr = "EXC_MACH_SYSCALL"; - break; - case 9: - exc_cstr = "EXC_RPC_ALERT"; - break; - case 10: - exc_cstr = "EXC_CRASH"; - break; - default: - break; - } - - s.Printf("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), " - "subcode = %u (0x%8.8x)} ", - cpu, exc_cstr, exc, code, code, subcode, subcode); - } - } break; - - case KDP_TERMINATION: { - const uint32_t term_code = packet.GetU32(&offset); - const uint32_t exit_code = packet.GetU32(&offset); - s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))", - term_code, term_code, exit_code, exit_code); - } break; - - case KDP_REATTACH: { - const uint16_t reply_port = ntohs(packet.GetU16(&offset)); - s.Printf(" (reply_port = %u)", reply_port); - } break; - - case KDP_READMSR64: { - const uint32_t address = packet.GetU32(&offset); - const uint16_t lcpu = packet.GetU16(&offset); - s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu); - } break; - - case KDP_WRITEMSR64: { - const uint32_t address = packet.GetU32(&offset); - const uint16_t lcpu = packet.GetU16(&offset); - const uint32_t nbytes = packet.GetByteSize() - offset; - s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu, - address, nbytes); - if (nbytes > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - 1, // Size of each item in - // bytes - nbytes, // Number of items - 16, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses - // before each line - 0, 0); // No bitfields - } break; - - case KDP_READIOPORT: { - const uint16_t lcpu = packet.GetU16(&offset); - const uint16_t address = packet.GetU16(&offset); - const uint16_t nbytes = packet.GetU16(&offset); - s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address, - nbytes); - } break; - - case KDP_WRITEIOPORT: { - const uint16_t lcpu = packet.GetU16(&offset); - const uint16_t address = packet.GetU16(&offset); - const uint16_t nbytes = packet.GetU16(&offset); - s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu, - address, nbytes); - if (nbytes > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - 1, // Size of each item in - // bytes - nbytes, // Number of items - 16, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses - // before each line - 0, 0); // No bitfields - } break; - - case KDP_DUMPINFO: { - const uint32_t count = packet.GetByteSize() - offset; - s.Printf(" (count = %u, bytes = \n", count); - if (count > 0) - DumpDataExtractor(packet, - &s, // Stream to dump to - offset, // Offset within "packet" - eFormatHex, // Format to use - 1, // Size of each item in bytes - count, // Number of items - 16, // Number per line - LLDB_INVALID_ADDRESS, // Don't show addresses before each line - 0, 0); // No bitfields - - } break; - } - } - } else { - error_desc = "error: invalid packet command: "; - } - } - - if (error_desc) { - s.PutCString(error_desc); - - DumpDataExtractor(packet, - &s, // Stream to dump to - 0, // Offset into "packet" - eFormatBytes, // Dump as hex bytes - 1, // Size of each item is 1 for - // single bytes - packet.GetByteSize(), // Number of bytes - UINT32_MAX, // Num bytes per line - LLDB_INVALID_ADDRESS, // Base address - 0, 0); // Bitfield info set to not do - // anything bitfield related - } -} - -uint32_t CommunicationKDP::SendRequestReadRegisters(uint32_t cpu, - uint32_t flavor, void *dst, - uint32_t dst_len, - Status &error) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_READREGS; - // Size is header + 4 byte cpu and 4 byte flavor - const uint32_t command_length = 8 + 4 + 4; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutHex32(cpu); - request_packet.PutHex32(flavor); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - uint32_t src_len = reply_packet.GetByteSize() - 12; - - if (src_len > 0) { - const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len); - const void *src = reply_packet.GetData(&offset, bytes_to_copy); - if (src) { - ::memcpy(dst, src, bytes_to_copy); - error.Clear(); - // Return the number of bytes we could have returned regardless if we - // copied them or not, just so we know when things don't match up - return src_len; - } - } - if (kdp_error) - error.SetErrorStringWithFormat( - "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, - flavor, kdp_error); - else - error.SetErrorStringWithFormat( - "failed to read kdp registers for cpu %u flavor %u", cpu, flavor); - } else { - error.SetErrorString("failed to send packet"); - } - return 0; -} - -uint32_t CommunicationKDP::SendRequestWriteRegisters(uint32_t cpu, - uint32_t flavor, - const void *src, - uint32_t src_len, - Status &error) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_WRITEREGS; - // Size is header + 4 byte cpu and 4 byte flavor - const uint32_t command_length = 8 + 4 + 4 + src_len; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutHex32(cpu); - request_packet.PutHex32(flavor); - request_packet.Write(src, src_len); - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - if (kdp_error == 0) - return src_len; - error.SetErrorStringWithFormat( - "failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, - flavor, kdp_error); - } else { - error.SetErrorString("failed to send packet"); - } - return 0; -} - -bool CommunicationKDP::SendRequestResume() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_RESUMECPUS; - const uint32_t command_length = 12; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutHex32(GetCPUMask()); - - DataExtractor reply_packet; - return SendRequestAndGetReply(command, request_packet, reply_packet); -} - -bool CommunicationKDP::SendRequestBreakpoint(bool set, addr_t addr) { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - bool use_64 = (GetVersion() >= 11); - uint32_t command_addr_byte_size = use_64 ? 8 : 4; - const CommandType command = - set ? (use_64 ? KDP_BREAKPOINT_SET64 : KDP_BREAKPOINT_SET) - : (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE); - - const uint32_t command_length = 8 + command_addr_byte_size; - MakeRequestPacketHeader(command, request_packet, command_length); - request_packet.PutMaxHex64(addr, command_addr_byte_size); - - DataExtractor reply_packet; - if (SendRequestAndGetReply(command, request_packet, reply_packet)) { - lldb::offset_t offset = 8; - uint32_t kdp_error = reply_packet.GetU32(&offset); - if (kdp_error == 0) - return true; - } - return false; -} - -bool CommunicationKDP::SendRequestSuspend() { - PacketStreamType request_packet(Stream::eBinary, m_addr_byte_size, - m_byte_order); - const CommandType command = KDP_SUSPEND; - const uint32_t command_length = 8; - MakeRequestPacketHeader(command, request_packet, command_length); - DataExtractor reply_packet; - return SendRequestAndGetReply(command, request_packet, reply_packet); -} diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h deleted file mode 100644 index 64bfe55147350..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ /dev/null @@ -1,260 +0,0 @@ -//===-- CommunicationKDP.h --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_CommunicationKDP_h_ -#define liblldb_CommunicationKDP_h_ - -#include <list> -#include <mutex> -#include <string> - -#include "lldb/Core/Communication.h" -#include "lldb/Core/StreamBuffer.h" -#include "lldb/Utility/Listener.h" -#include "lldb/Utility/Predicate.h" -#include "lldb/lldb-private.h" - -class CommunicationKDP : public lldb_private::Communication { -public: - enum { eBroadcastBitRunPacketSent = kLoUserBroadcastBit }; - - const static uint32_t kMaxPacketSize = 1200; - const static uint32_t kMaxDataSize = 1024; - typedef lldb_private::StreamBuffer<1024> PacketStreamType; - typedef enum { - KDP_CONNECT = 0u, - KDP_DISCONNECT, - KDP_HOSTINFO, - KDP_VERSION, - KDP_MAXBYTES, - KDP_READMEM, - KDP_WRITEMEM, - KDP_READREGS, - KDP_WRITEREGS, - KDP_LOAD, - KDP_IMAGEPATH, - KDP_SUSPEND, - KDP_RESUMECPUS, - KDP_EXCEPTION, - KDP_TERMINATION, - KDP_BREAKPOINT_SET, - KDP_BREAKPOINT_REMOVE, - KDP_REGIONS, - KDP_REATTACH, - KDP_HOSTREBOOT, - KDP_READMEM64, - KDP_WRITEMEM64, - KDP_BREAKPOINT_SET64, - KDP_BREAKPOINT_REMOVE64, - KDP_KERNELVERSION, - KDP_READPHYSMEM64, - KDP_WRITEPHYSMEM64, - KDP_READIOPORT, - KDP_WRITEIOPORT, - KDP_READMSR64, - KDP_WRITEMSR64, - KDP_DUMPINFO - } CommandType; - - enum { KDP_FEATURE_BP = (1u << 0) }; - - typedef enum { - KDP_PROTERR_SUCCESS = 0, - KDP_PROTERR_ALREADY_CONNECTED, - KDP_PROTERR_BAD_NBYTES, - KDP_PROTERR_BADFLAVOR - } KDPError; - - typedef enum { - ePacketTypeRequest = 0x00u, - ePacketTypeReply = 0x80u, - ePacketTypeMask = 0x80u, - eCommandTypeMask = 0x7fu - } PacketType; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - CommunicationKDP(const char *comm_name); - - virtual ~CommunicationKDP(); - - bool SendRequestPacket(const PacketStreamType &request_packet); - - // Wait for a packet within 'nsec' seconds - size_t - WaitForPacketWithTimeoutMicroSeconds(lldb_private::DataExtractor &response, - uint32_t usec); - - bool GetSequenceMutex(std::unique_lock<std::recursive_mutex> &lock); - - bool CheckForPacket(const uint8_t *src, size_t src_len, - lldb_private::DataExtractor &packet); - bool IsRunning() const { return m_is_running.GetValue(); } - - //------------------------------------------------------------------ - // Set the global packet timeout. - // - // For clients, this is the timeout that gets used when sending - // packets and waiting for responses. For servers, this might not - // get used, and if it doesn't this should be moved to the - // CommunicationKDPClient. - //------------------------------------------------------------------ - std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { - const auto old_packet_timeout = m_packet_timeout; - m_packet_timeout = packet_timeout; - return old_packet_timeout; - } - - std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } - - //------------------------------------------------------------------ - // Public Request Packets - //------------------------------------------------------------------ - bool SendRequestConnect(uint16_t reply_port, uint16_t exc_port, - const char *greeting); - - bool SendRequestReattach(uint16_t reply_port); - - bool SendRequestDisconnect(); - - uint32_t SendRequestReadMemory(lldb::addr_t addr, void *dst, - uint32_t dst_size, - lldb_private::Status &error); - - uint32_t SendRequestWriteMemory(lldb::addr_t addr, const void *src, - uint32_t src_len, - lldb_private::Status &error); - - bool SendRawRequest(uint8_t command_byte, const void *src, uint32_t src_len, - lldb_private::DataExtractor &reply, - lldb_private::Status &error); - - uint32_t SendRequestReadRegisters(uint32_t cpu, uint32_t flavor, void *dst, - uint32_t dst_size, - lldb_private::Status &error); - - uint32_t SendRequestWriteRegisters(uint32_t cpu, uint32_t flavor, - const void *src, uint32_t src_size, - lldb_private::Status &error); - - const char *GetKernelVersion(); - - // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... - // const char * - // GetImagePath (); - - uint32_t GetVersion(); - - uint32_t GetFeatureFlags(); - - bool LocalBreakpointsAreSupported() { - return (GetFeatureFlags() & KDP_FEATURE_BP) != 0; - } - - uint32_t GetCPUMask(); - - uint32_t GetCPUType(); - - uint32_t GetCPUSubtype(); - - lldb_private::UUID GetUUID(); - - bool RemoteIsEFI(); - - bool RemoteIsDarwinKernel(); - - lldb::addr_t GetLoadAddress(); - - bool SendRequestResume(); - - bool SendRequestSuspend(); - - bool SendRequestBreakpoint(bool set, lldb::addr_t addr); - -protected: - bool SendRequestPacketNoLock(const PacketStreamType &request_packet); - - size_t WaitForPacketWithTimeoutMicroSecondsNoLock( - lldb_private::DataExtractor &response, uint32_t timeout_usec); - - bool WaitForNotRunningPrivate(const std::chrono::microseconds &timeout); - - void MakeRequestPacketHeader(CommandType request_type, - PacketStreamType &request_packet, - uint16_t request_length); - - //------------------------------------------------------------------ - // Protected Request Packets (use public accessors which will cache - // results. - //------------------------------------------------------------------ - bool SendRequestVersion(); - - bool SendRequestHostInfo(); - - bool SendRequestKernelVersion(); - - // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... - // bool - // SendRequestImagePath (); - - void DumpPacket(lldb_private::Stream &s, const void *data, uint32_t data_len); - - void DumpPacket(lldb_private::Stream &s, - const lldb_private::DataExtractor &extractor); - - bool VersionIsValid() const { return m_kdp_version_version != 0; } - - bool HostInfoIsValid() const { return m_kdp_hostinfo_cpu_type != 0; } - - bool ExtractIsReply(uint8_t first_packet_byte) const { - // TODO: handle big endian... - return (first_packet_byte & ePacketTypeMask) != 0; - } - - CommandType ExtractCommand(uint8_t first_packet_byte) const { - // TODO: handle big endian... - return (CommandType)(first_packet_byte & eCommandTypeMask); - } - - static const char *GetCommandAsCString(uint8_t command); - - void ClearKDPSettings(); - - bool SendRequestAndGetReply(const CommandType command, - const PacketStreamType &request_packet, - lldb_private::DataExtractor &reply_packet); - //------------------------------------------------------------------ - // Classes that inherit from CommunicationKDP can see and modify these - //------------------------------------------------------------------ - uint32_t m_addr_byte_size; - lldb::ByteOrder m_byte_order; - std::chrono::seconds m_packet_timeout; - std::recursive_mutex m_sequence_mutex; // Restrict access to sending/receiving - // packets to a single thread at a time - lldb_private::Predicate<bool> m_is_running; - uint32_t m_session_key; - uint8_t m_request_sequence_id; - uint8_t m_exception_sequence_id; - uint32_t m_kdp_version_version; - uint32_t m_kdp_version_feature; - uint32_t m_kdp_hostinfo_cpu_mask; - uint32_t m_kdp_hostinfo_cpu_type; - uint32_t m_kdp_hostinfo_cpu_subtype; - std::string m_kernel_version; - // std::string m_image_path; // Disable KDP_IMAGEPATH for now, it seems to - // hang the KDP connection... - lldb::addr_t m_last_read_memory_addr; // Last memory read address for logging -private: - //------------------------------------------------------------------ - // For CommunicationKDP only - //------------------------------------------------------------------ - DISALLOW_COPY_AND_ASSIGN(CommunicationKDP); -}; - -#endif // liblldb_CommunicationKDP_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp deleted file mode 100644 index c1c3678617c09..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ /dev/null @@ -1,1037 +0,0 @@ -//===-- ProcessKDP.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <errno.h> -#include <stdlib.h> - -#include <mutex> - -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Host/ConnectionFileDescriptor.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/Symbols.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/common/TCPSocket.h" -#include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/CommandObject.h" -#include "lldb/Interpreter/CommandObjectMultiword.h" -#include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/OptionGroupString.h" -#include "lldb/Interpreter/OptionGroupUInt64.h" -#include "lldb/Interpreter/OptionValueProperties.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/StringExtractor.h" -#include "lldb/Utility/UUID.h" - -#include "llvm/Support/Threading.h" - -#define USEC_PER_SEC 1000000 - -#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" -#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" -#include "ProcessKDP.h" -#include "ProcessKDPLog.h" -#include "ThreadKDP.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { - -static constexpr PropertyDefinition g_properties[] = { - {"packet-timeout", OptionValue::eTypeUInt64, true, 5, NULL, {}, - "Specify the default packet timeout in seconds."}}; - -enum { ePropertyPacketTimeout }; - -class PluginProperties : public Properties { -public: - static ConstString GetSettingName() { - return ProcessKDP::GetPluginNameStatic(); - } - - PluginProperties() : Properties() { - m_collection_sp.reset(new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - virtual ~PluginProperties() {} - - uint64_t GetPacketTimeout() { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->GetPropertyAtIndexAsUInt64( - NULL, idx, g_properties[idx].default_uint_value); - } -}; - -typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; - -static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { - static ProcessKDPPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset(new PluginProperties()); - return g_settings_sp; -} - -} // anonymous namespace end - -static const lldb::tid_t g_kernel_tid = 1; - -ConstString ProcessKDP::GetPluginNameStatic() { - static ConstString g_name("kdp-remote"); - return g_name; -} - -const char *ProcessKDP::GetPluginDescriptionStatic() { - return "KDP Remote protocol based debugging plug-in for darwin kernel " - "debugging."; -} - -void ProcessKDP::Terminate() { - PluginManager::UnregisterPlugin(ProcessKDP::CreateInstance); -} - -lldb::ProcessSP ProcessKDP::CreateInstance(TargetSP target_sp, - ListenerSP listener_sp, - const FileSpec *crash_file_path) { - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset(new ProcessKDP(target_sp, listener_sp)); - return process_sp; -} - -bool ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) { - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) { - const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple(); - switch (triple_ref.getOS()) { - case llvm::Triple::Darwin: // Should use "macosx" for desktop and "ios" for - // iOS, but accept darwin just in case - case llvm::Triple::MacOSX: // For desktop targets - case llvm::Triple::IOS: // For arm targets - case llvm::Triple::TvOS: - case llvm::Triple::WatchOS: - if (triple_ref.getVendor() == llvm::Triple::Apple) { - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && - exe_objfile->GetStrata() == ObjectFile::eStrataKernel) - return true; - } - break; - - default: - break; - } - } - return false; -} - -//---------------------------------------------------------------------- -// ProcessKDP constructor -//---------------------------------------------------------------------- -ProcessKDP::ProcessKDP(TargetSP target_sp, ListenerSP listener_sp) - : Process(target_sp, listener_sp), - m_comm("lldb.process.kdp-remote.communication"), - m_async_broadcaster(NULL, "lldb.process.kdp-remote.async-broadcaster"), - m_dyld_plugin_name(), m_kernel_load_addr(LLDB_INVALID_ADDRESS), - m_command_sp(), m_kernel_thread_wp() { - m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, - "async thread should exit"); - m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, - "async thread continue"); - const uint64_t timeout_seconds = - GetGlobalPluginProperties()->GetPacketTimeout(); - if (timeout_seconds > 0) - m_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); -} - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -ProcessKDP::~ProcessKDP() { - Clear(); - // We need to call finalize on the process before destroying ourselves to - // make sure all of the broadcaster cleanup goes as planned. If we destruct - // this class, then Process::~Process() might have problems trying to fully - // destroy the broadcaster. - Finalize(); -} - -//---------------------------------------------------------------------- -// PluginInterface -//---------------------------------------------------------------------- -lldb_private::ConstString ProcessKDP::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t ProcessKDP::GetPluginVersion() { return 1; } - -Status ProcessKDP::WillLaunch(Module *module) { - Status error; - error.SetErrorString("launching not supported in kdp-remote plug-in"); - return error; -} - -Status ProcessKDP::WillAttachToProcessWithID(lldb::pid_t pid) { - Status error; - error.SetErrorString( - "attaching to a by process ID not supported in kdp-remote plug-in"); - return error; -} - -Status ProcessKDP::WillAttachToProcessWithName(const char *process_name, - bool wait_for_launch) { - Status error; - error.SetErrorString( - "attaching to a by process name not supported in kdp-remote plug-in"); - return error; -} - -bool ProcessKDP::GetHostArchitecture(ArchSpec &arch) { - uint32_t cpu = m_comm.GetCPUType(); - if (cpu) { - uint32_t sub = m_comm.GetCPUSubtype(); - arch.SetArchitecture(eArchTypeMachO, cpu, sub); - // Leave architecture vendor as unspecified unknown - arch.GetTriple().setVendor(llvm::Triple::UnknownVendor); - arch.GetTriple().setVendorName(llvm::StringRef()); - return true; - } - arch.Clear(); - return false; -} - -Status ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { - Status error; - - // Don't let any JIT happen when doing KDP as we can't allocate memory and we - // don't want to be mucking with threads that might already be handling - // exceptions - SetCanJIT(false); - - if (remote_url.empty()) { - error.SetErrorStringWithFormat("empty connection URL"); - return error; - } - - std::unique_ptr<ConnectionFileDescriptor> conn_ap( - new ConnectionFileDescriptor()); - if (conn_ap.get()) { - // Only try once for now. - // TODO: check if we should be retrying? - const uint32_t max_retry_count = 1; - for (uint32_t retry_count = 0; retry_count < max_retry_count; - ++retry_count) { - if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess) - break; - usleep(100000); - } - } - - if (conn_ap->IsConnected()) { - const TCPSocket &socket = - static_cast<const TCPSocket &>(*conn_ap->GetReadObject()); - const uint16_t reply_port = socket.GetLocalPortNumber(); - - if (reply_port != 0) { - m_comm.SetConnection(conn_ap.release()); - - if (m_comm.SendRequestReattach(reply_port)) { - if (m_comm.SendRequestConnect(reply_port, reply_port, - "Greetings from LLDB...")) { - m_comm.GetVersion(); - - Target &target = GetTarget(); - ArchSpec kernel_arch; - // The host architecture - GetHostArchitecture(kernel_arch); - ArchSpec target_arch = target.GetArchitecture(); - // Merge in any unspecified stuff into the target architecture in - // case the target arch isn't set at all or incompletely. - target_arch.MergeFrom(kernel_arch); - target.SetArchitecture(target_arch); - - /* Get the kernel's UUID and load address via KDP_KERNELVERSION - * packet. */ - /* An EFI kdp session has neither UUID nor load address. */ - - UUID kernel_uuid = m_comm.GetUUID(); - addr_t kernel_load_addr = m_comm.GetLoadAddress(); - - if (m_comm.RemoteIsEFI()) { - // Select an invalid plugin name for the dynamic loader so one - // doesn't get used since EFI does its own manual loading via - // python scripting - static ConstString g_none_dynamic_loader("none"); - m_dyld_plugin_name = g_none_dynamic_loader; - - if (kernel_uuid.IsValid()) { - // If EFI passed in a UUID= try to lookup UUID The slide will not - // be provided. But the UUID lookup will be used to launch EFI - // debug scripts from the dSYM, that can load all of the symbols. - ModuleSpec module_spec; - module_spec.GetUUID() = kernel_uuid; - module_spec.GetArchitecture() = target.GetArchitecture(); - - // Lookup UUID locally, before attempting dsymForUUID like action - module_spec.GetSymbolFileSpec() = - Symbols::LocateExecutableSymbolFile(module_spec); - if (module_spec.GetSymbolFileSpec()) { - ModuleSpec executable_module_spec = - Symbols::LocateExecutableObjectFile(module_spec); - if (FileSystem::Instance().Exists( - executable_module_spec.GetFileSpec())) { - module_spec.GetFileSpec() = - executable_module_spec.GetFileSpec(); - } - } - if (!module_spec.GetSymbolFileSpec() || - !module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile(module_spec, true); - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - ModuleSP module_sp(new Module(module_spec)); - if (module_sp.get() && module_sp->GetObjectFile()) { - // Get the current target executable - ModuleSP exe_module_sp(target.GetExecutableModule()); - - // Make sure you don't already have the right module loaded - // and they will be uniqued - if (exe_module_sp.get() != module_sp.get()) - target.SetExecutableModule(module_sp, eLoadDependentsNo); - } - } - } - } else if (m_comm.RemoteIsDarwinKernel()) { - m_dyld_plugin_name = - DynamicLoaderDarwinKernel::GetPluginNameStatic(); - if (kernel_load_addr != LLDB_INVALID_ADDRESS) { - m_kernel_load_addr = kernel_load_addr; - } - } - - // Set the thread ID - UpdateThreadListIfNeeded(); - SetID(1); - GetThreadList(); - SetPrivateState(eStateStopped); - StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream()); - if (async_strm_sp) { - const char *cstr; - if ((cstr = m_comm.GetKernelVersion()) != NULL) { - async_strm_sp->Printf("Version: %s\n", cstr); - async_strm_sp->Flush(); - } - // if ((cstr = m_comm.GetImagePath ()) != NULL) - // { - // async_strm_sp->Printf ("Image Path: - // %s\n", cstr); - // async_strm_sp->Flush(); - // } - } - } else { - error.SetErrorString("KDP_REATTACH failed"); - } - } else { - error.SetErrorString("KDP_REATTACH failed"); - } - } else { - error.SetErrorString("invalid reply port from UDP connection"); - } - } else { - if (error.Success()) - error.SetErrorStringWithFormat("failed to connect to '%s'", - remote_url.str().c_str()); - } - if (error.Fail()) - m_comm.Disconnect(); - - return error; -} - -//---------------------------------------------------------------------- -// Process Control -//---------------------------------------------------------------------- -Status ProcessKDP::DoLaunch(Module *exe_module, - ProcessLaunchInfo &launch_info) { - Status error; - error.SetErrorString("launching not supported in kdp-remote plug-in"); - return error; -} - -Status -ProcessKDP::DoAttachToProcessWithID(lldb::pid_t attach_pid, - const ProcessAttachInfo &attach_info) { - Status error; - error.SetErrorString( - "attach to process by ID is not supported in kdp remote debugging"); - return error; -} - -Status -ProcessKDP::DoAttachToProcessWithName(const char *process_name, - const ProcessAttachInfo &attach_info) { - Status error; - error.SetErrorString( - "attach to process by name is not supported in kdp remote debugging"); - return error; -} - -void ProcessKDP::DidAttach(ArchSpec &process_arch) { - Process::DidAttach(process_arch); - - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (log) - log->Printf("ProcessKDP::DidAttach()"); - if (GetID() != LLDB_INVALID_PROCESS_ID) { - GetHostArchitecture(process_arch); - } -} - -addr_t ProcessKDP::GetImageInfoAddress() { return m_kernel_load_addr; } - -lldb_private::DynamicLoader *ProcessKDP::GetDynamicLoader() { - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset(DynamicLoader::FindPlugin( - this, - m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString())); - return m_dyld_ap.get(); -} - -Status ProcessKDP::WillResume() { return Status(); } - -Status ProcessKDP::DoResume() { - Status error; - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - // Only start the async thread if we try to do any process control - if (!m_async_thread.IsJoinable()) - StartAsyncThread(); - - bool resume = false; - - // With KDP there is only one thread we can tell what to do - ThreadSP kernel_thread_sp(m_thread_list.FindThreadByProtocolID(g_kernel_tid)); - - if (kernel_thread_sp) { - const StateType thread_resume_state = - kernel_thread_sp->GetTemporaryResumeState(); - - if (log) - log->Printf("ProcessKDP::DoResume() thread_resume_state = %s", - StateAsCString(thread_resume_state)); - switch (thread_resume_state) { - case eStateSuspended: - // Nothing to do here when a thread will stay suspended we just leave the - // CPU mask bit set to zero for the thread - if (log) - log->Printf("ProcessKDP::DoResume() = suspended???"); - break; - - case eStateStepping: { - lldb::RegisterContextSP reg_ctx_sp( - kernel_thread_sp->GetRegisterContext()); - - if (reg_ctx_sp) { - if (log) - log->Printf( - "ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);"); - reg_ctx_sp->HardwareSingleStep(true); - resume = true; - } else { - error.SetErrorStringWithFormat( - "KDP thread 0x%llx has no register context", - kernel_thread_sp->GetID()); - } - } break; - - case eStateRunning: { - lldb::RegisterContextSP reg_ctx_sp( - kernel_thread_sp->GetRegisterContext()); - - if (reg_ctx_sp) { - if (log) - log->Printf("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep " - "(false);"); - reg_ctx_sp->HardwareSingleStep(false); - resume = true; - } else { - error.SetErrorStringWithFormat( - "KDP thread 0x%llx has no register context", - kernel_thread_sp->GetID()); - } - } break; - - default: - // The only valid thread resume states are listed above - llvm_unreachable("invalid thread resume state"); - } - } - - if (resume) { - if (log) - log->Printf("ProcessKDP::DoResume () sending resume"); - - if (m_comm.SendRequestResume()) { - m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); - SetPrivateState(eStateRunning); - } else - error.SetErrorString("KDP resume failed"); - } else { - error.SetErrorString("kernel thread is suspended"); - } - - return error; -} - -lldb::ThreadSP ProcessKDP::GetKernelThread() { - // KDP only tells us about one thread/core. Any other threads will usually - // be the ones that are read from memory by the OS plug-ins. - - ThreadSP thread_sp(m_kernel_thread_wp.lock()); - if (!thread_sp) { - thread_sp.reset(new ThreadKDP(*this, g_kernel_tid)); - m_kernel_thread_wp = thread_sp; - } - return thread_sp; -} - -bool ProcessKDP::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { - // locker will keep a mutex locked until it goes out of scope - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD)); - LLDB_LOGV(log, "pid = {0}", GetID()); - - // Even though there is a CPU mask, it doesn't mean we can see each CPU - // individually, there is really only one. Lets call this thread 1. - ThreadSP thread_sp( - old_thread_list.FindThreadByProtocolID(g_kernel_tid, false)); - if (!thread_sp) - thread_sp = GetKernelThread(); - new_thread_list.AddThread(thread_sp); - - return new_thread_list.GetSize(false) > 0; -} - -void ProcessKDP::RefreshStateAfterStop() { - // Let all threads recover from stopping and do any clean up based on the - // previous thread state (if any). - m_thread_list.RefreshStateAfterStop(); -} - -Status ProcessKDP::DoHalt(bool &caused_stop) { - Status error; - - if (m_comm.IsRunning()) { - if (m_destroy_in_process) { - // If we are attempting to destroy, we need to not return an error to Halt - // or DoDestroy won't get called. We are also currently running, so send - // a process stopped event - SetPrivateState(eStateStopped); - } else { - error.SetErrorString("KDP cannot interrupt a running kernel"); - } - } - return error; -} - -Status ProcessKDP::DoDetach(bool keep_stopped) { - Status error; - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (log) - log->Printf("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); - - if (m_comm.IsRunning()) { - // We are running and we can't interrupt a running kernel, so we need to - // just close the connection to the kernel and hope for the best - } else { - // If we are going to keep the target stopped, then don't send the - // disconnect message. - if (!keep_stopped && m_comm.IsConnected()) { - const bool success = m_comm.SendRequestDisconnect(); - if (log) { - if (success) - log->PutCString( - "ProcessKDP::DoDetach() detach packet sent successfully"); - else - log->PutCString( - "ProcessKDP::DoDetach() connection channel shutdown failed"); - } - m_comm.Disconnect(); - } - } - StopAsyncThread(); - m_comm.Clear(); - - SetPrivateState(eStateDetached); - ResumePrivateStateThread(); - - // KillDebugserverProcess (); - return error; -} - -Status ProcessKDP::DoDestroy() { - // For KDP there really is no difference between destroy and detach - bool keep_stopped = false; - return DoDetach(keep_stopped); -} - -//------------------------------------------------------------------ -// Process Queries -//------------------------------------------------------------------ - -bool ProcessKDP::IsAlive() { - return m_comm.IsConnected() && Process::IsAlive(); -} - -//------------------------------------------------------------------ -// Process Memory -//------------------------------------------------------------------ -size_t ProcessKDP::DoReadMemory(addr_t addr, void *buf, size_t size, - Status &error) { - uint8_t *data_buffer = (uint8_t *)buf; - if (m_comm.IsConnected()) { - const size_t max_read_size = 512; - size_t total_bytes_read = 0; - - // Read the requested amount of memory in 512 byte chunks - while (total_bytes_read < size) { - size_t bytes_to_read_this_request = size - total_bytes_read; - if (bytes_to_read_this_request > max_read_size) { - bytes_to_read_this_request = max_read_size; - } - size_t bytes_read = m_comm.SendRequestReadMemory( - addr + total_bytes_read, data_buffer + total_bytes_read, - bytes_to_read_this_request, error); - total_bytes_read += bytes_read; - if (error.Fail() || bytes_read == 0) { - return total_bytes_read; - } - } - - return total_bytes_read; - } - error.SetErrorString("not connected"); - return 0; -} - -size_t ProcessKDP::DoWriteMemory(addr_t addr, const void *buf, size_t size, - Status &error) { - if (m_comm.IsConnected()) - return m_comm.SendRequestWriteMemory(addr, buf, size, error); - error.SetErrorString("not connected"); - return 0; -} - -lldb::addr_t ProcessKDP::DoAllocateMemory(size_t size, uint32_t permissions, - Status &error) { - error.SetErrorString( - "memory allocation not supported in kdp remote debugging"); - return LLDB_INVALID_ADDRESS; -} - -Status ProcessKDP::DoDeallocateMemory(lldb::addr_t addr) { - Status error; - error.SetErrorString( - "memory deallocation not supported in kdp remote debugging"); - return error; -} - -Status ProcessKDP::EnableBreakpointSite(BreakpointSite *bp_site) { - if (m_comm.LocalBreakpointsAreSupported()) { - Status error; - if (!bp_site->IsEnabled()) { - if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress())) { - bp_site->SetEnabled(true); - bp_site->SetType(BreakpointSite::eExternal); - } else { - error.SetErrorString("KDP set breakpoint failed"); - } - } - return error; - } - return EnableSoftwareBreakpoint(bp_site); -} - -Status ProcessKDP::DisableBreakpointSite(BreakpointSite *bp_site) { - if (m_comm.LocalBreakpointsAreSupported()) { - Status error; - if (bp_site->IsEnabled()) { - BreakpointSite::Type bp_type = bp_site->GetType(); - if (bp_type == BreakpointSite::eExternal) { - if (m_destroy_in_process && m_comm.IsRunning()) { - // We are trying to destroy our connection and we are running - bp_site->SetEnabled(false); - } else { - if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) - bp_site->SetEnabled(false); - else - error.SetErrorString("KDP remove breakpoint failed"); - } - } else { - error = DisableSoftwareBreakpoint(bp_site); - } - } - return error; - } - return DisableSoftwareBreakpoint(bp_site); -} - -Status ProcessKDP::EnableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - error.SetErrorString( - "watchpoints are not supported in kdp remote debugging"); - return error; -} - -Status ProcessKDP::DisableWatchpoint(Watchpoint *wp, bool notify) { - Status error; - error.SetErrorString( - "watchpoints are not supported in kdp remote debugging"); - return error; -} - -void ProcessKDP::Clear() { m_thread_list.Clear(); } - -Status ProcessKDP::DoSignal(int signo) { - Status error; - error.SetErrorString( - "sending signals is not supported in kdp remote debugging"); - return error; -} - -void ProcessKDP::Initialize() { - static llvm::once_flag g_once_flag; - - llvm::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance, - DebuggerInitialize); - - ProcessKDPLog::Initialize(); - }); -} - -void ProcessKDP::DebuggerInitialize(lldb_private::Debugger &debugger) { - if (!PluginManager::GetSettingForProcessPlugin( - debugger, PluginProperties::GetSettingName())) { - const bool is_global_setting = true; - PluginManager::CreateSettingForProcessPlugin( - debugger, GetGlobalPluginProperties()->GetValueProperties(), - ConstString("Properties for the kdp-remote process plug-in."), - is_global_setting); - } -} - -bool ProcessKDP::StartAsyncThread() { - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - - if (log) - log->Printf("ProcessKDP::StartAsyncThread ()"); - - if (m_async_thread.IsJoinable()) - return true; - - m_async_thread = ThreadLauncher::LaunchThread( - "<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL); - return m_async_thread.IsJoinable(); -} - -void ProcessKDP::StopAsyncThread() { - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - - if (log) - log->Printf("ProcessKDP::StopAsyncThread ()"); - - m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); - - // Stop the stdio thread - if (m_async_thread.IsJoinable()) - m_async_thread.Join(nullptr); -} - -void *ProcessKDP::AsyncThread(void *arg) { - ProcessKDP *process = (ProcessKDP *)arg; - - const lldb::pid_t pid = process->GetID(); - - Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (log) - log->Printf("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 - ") thread starting...", - arg, pid); - - ListenerSP listener_sp(Listener::MakeListener("ProcessKDP::AsyncThread")); - EventSP event_sp; - const uint32_t desired_event_mask = - eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; - - if (listener_sp->StartListeningForEvents(&process->m_async_broadcaster, - desired_event_mask) == - desired_event_mask) { - bool done = false; - while (!done) { - if (log) - log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 - ") listener.WaitForEvent (NULL, event_sp)...", - pid); - if (listener_sp->GetEvent(event_sp, llvm::None)) { - uint32_t event_type = event_sp->GetType(); - if (log) - log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 - ") Got an event of type: %d...", - pid, event_type); - - // When we are running, poll for 1 second to try and get an exception - // to indicate the process has stopped. If we don't get one, check to - // make sure no one asked us to exit - bool is_running = false; - DataExtractor exc_reply_packet; - do { - switch (event_type) { - case eBroadcastBitAsyncContinue: { - is_running = true; - if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds( - exc_reply_packet, 1 * USEC_PER_SEC)) { - ThreadSP thread_sp(process->GetKernelThread()); - if (thread_sp) { - lldb::RegisterContextSP reg_ctx_sp( - thread_sp->GetRegisterContext()); - if (reg_ctx_sp) - reg_ctx_sp->InvalidateAllRegisters(); - static_cast<ThreadKDP *>(thread_sp.get()) - ->SetStopInfoFrom_KDP_EXCEPTION(exc_reply_packet); - } - - // TODO: parse the stop reply packet - is_running = false; - process->SetPrivateState(eStateStopped); - } else { - // Check to see if we are supposed to exit. There is no way to - // interrupt a running kernel, so all we can do is wait for an - // exception or detach... - if (listener_sp->GetEvent(event_sp, - std::chrono::microseconds(0))) { - // We got an event, go through the loop again - event_type = event_sp->GetType(); - } - } - } break; - - case eBroadcastBitAsyncThreadShouldExit: - if (log) - log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 - ") got eBroadcastBitAsyncThreadShouldExit...", - pid); - done = true; - is_running = false; - break; - - default: - if (log) - log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 - ") got unknown event 0x%8.8x", - pid, event_type); - done = true; - is_running = false; - break; - } - } while (is_running); - } else { - if (log) - log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 - ") listener.WaitForEvent (NULL, event_sp) => false", - pid); - done = true; - } - } - } - - if (log) - log->Printf("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 - ") thread exiting...", - arg, pid); - - process->m_async_thread.Reset(); - return NULL; -} - -class CommandObjectProcessKDPPacketSend : public CommandObjectParsed { -private: - OptionGroupOptions m_option_group; - OptionGroupUInt64 m_command_byte; - OptionGroupString m_packet_data; - - virtual Options *GetOptions() { return &m_option_group; } - -public: - CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "process plugin packet send", - "Send a custom packet through the KDP protocol by " - "specifying the command byte and the packet " - "payload data. A packet will be sent with a " - "correct header and payload, and the raw result " - "bytes will be displayed as a string value. ", - NULL), - m_option_group(), - m_command_byte(LLDB_OPT_SET_1, true, "command", 'c', 0, eArgTypeNone, - "Specify the command byte to use when sending the KDP " - "request packet.", - 0), - m_packet_data(LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, - "Specify packet payload bytes as a hex ASCII string with " - "no spaces or hex prefixes.", - NULL) { - m_option_group.Append(&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append(&m_packet_data, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Finalize(); - } - - ~CommandObjectProcessKDPPacketSend() {} - - bool DoExecute(Args &command, CommandReturnObject &result) { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) { - if (!m_command_byte.GetOptionValue().OptionWasSet()) { - result.AppendError( - "the --command option must be set to a valid command byte"); - result.SetStatus(eReturnStatusFailed); - } else { - const uint64_t command_byte = - m_command_byte.GetOptionValue().GetUInt64Value(0); - if (command_byte > 0 && command_byte <= UINT8_MAX) { - ProcessKDP *process = - (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) { - const StateType state = process->GetState(); - - if (StateIsStoppedState(state, true)) { - std::vector<uint8_t> payload_bytes; - const char *ascii_hex_bytes_cstr = - m_packet_data.GetOptionValue().GetCurrentValue(); - if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) { - StringExtractor extractor(ascii_hex_bytes_cstr); - const size_t ascii_hex_bytes_cstr_len = - extractor.GetStringRef().size(); - if (ascii_hex_bytes_cstr_len & 1) { - result.AppendErrorWithFormat("payload data must contain an " - "even number of ASCII hex " - "characters: '%s'", - ascii_hex_bytes_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - payload_bytes.resize(ascii_hex_bytes_cstr_len / 2); - if (extractor.GetHexBytes(payload_bytes, '\xdd') != - payload_bytes.size()) { - result.AppendErrorWithFormat("payload data must only contain " - "ASCII hex characters (no " - "spaces or hex prefixes): '%s'", - ascii_hex_bytes_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - Status error; - DataExtractor reply; - process->GetCommunication().SendRawRequest( - command_byte, - payload_bytes.empty() ? NULL : payload_bytes.data(), - payload_bytes.size(), reply, error); - - if (error.Success()) { - // Copy the binary bytes into a hex ASCII string for the result - StreamString packet; - packet.PutBytesAsRawHex8( - reply.GetDataStart(), reply.GetByteSize(), - endian::InlHostByteOrder(), endian::InlHostByteOrder()); - result.AppendMessage(packet.GetString()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } else { - const char *error_cstr = error.AsCString(); - if (error_cstr && error_cstr[0]) - result.AppendError(error_cstr); - else - result.AppendErrorWithFormat("unknown error 0x%8.8x", - error.GetError()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } else { - result.AppendErrorWithFormat("process must be stopped in order " - "to send KDP packets, state is %s", - StateAsCString(state)); - result.SetStatus(eReturnStatusFailed); - } - } else { - result.AppendError("invalid process"); - result.SetStatus(eReturnStatusFailed); - } - } else { - result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64 - ", valid values are 1 - 255", - command_byte); - result.SetStatus(eReturnStatusFailed); - } - } - } else { - result.AppendErrorWithFormat("'%s' takes no arguments, only options.", - m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - } - return false; - } -}; - -class CommandObjectProcessKDPPacket : public CommandObjectMultiword { -private: -public: - CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "process plugin packet", - "Commands that deal with KDP remote packets.", - NULL) { - LoadSubCommand( - "send", - CommandObjectSP(new CommandObjectProcessKDPPacketSend(interpreter))); - } - - ~CommandObjectProcessKDPPacket() {} -}; - -class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword { -public: - CommandObjectMultiwordProcessKDP(CommandInterpreter &interpreter) - : CommandObjectMultiword( - interpreter, "process plugin", - "Commands for operating on a ProcessKDP process.", - "process plugin <subcommand> [<subcommand-options>]") { - LoadSubCommand("packet", CommandObjectSP(new CommandObjectProcessKDPPacket( - interpreter))); - } - - ~CommandObjectMultiwordProcessKDP() {} -}; - -CommandObject *ProcessKDP::GetPluginCommandObject() { - if (!m_command_sp) - m_command_sp.reset(new CommandObjectMultiwordProcessKDP( - GetTarget().GetDebugger().GetCommandInterpreter())); - return m_command_sp.get(); -} diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h deleted file mode 100644 index f9102442de935..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ /dev/null @@ -1,220 +0,0 @@ -//===-- ProcessKDP.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessKDP_h_ -#define liblldb_ProcessKDP_h_ - - -#include <list> -#include <vector> - -#include "lldb/Core/ThreadSafeValue.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/Broadcaster.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/StringList.h" - -#include "CommunicationKDP.h" - -class ThreadKDP; - -class ProcessKDP : public lldb_private::Process { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - static lldb::ProcessSP - CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); - - static void Initialize(); - - static void DebuggerInitialize(lldb_private::Debugger &debugger); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - ProcessKDP(lldb::TargetSP target_sp, lldb::ListenerSP listener); - - ~ProcessKDP() override; - - //------------------------------------------------------------------ - // Check if a given Process - //------------------------------------------------------------------ - bool CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) override; - lldb_private::CommandObject *GetPluginCommandObject() override; - - //------------------------------------------------------------------ - // Creating a new process, or attaching to an existing one - //------------------------------------------------------------------ - lldb_private::Status WillLaunch(lldb_private::Module *module) override; - - lldb_private::Status - DoLaunch(lldb_private::Module *exe_module, - lldb_private::ProcessLaunchInfo &launch_info) override; - - lldb_private::Status WillAttachToProcessWithID(lldb::pid_t pid) override; - - lldb_private::Status - WillAttachToProcessWithName(const char *process_name, - bool wait_for_launch) override; - - lldb_private::Status DoConnectRemote(lldb_private::Stream *strm, - llvm::StringRef remote_url) override; - - lldb_private::Status DoAttachToProcessWithID( - lldb::pid_t pid, - const lldb_private::ProcessAttachInfo &attach_info) override; - - lldb_private::Status DoAttachToProcessWithName( - const char *process_name, - const lldb_private::ProcessAttachInfo &attach_info) override; - - void DidAttach(lldb_private::ArchSpec &process_arch) override; - - lldb::addr_t GetImageInfoAddress() override; - - lldb_private::DynamicLoader *GetDynamicLoader() override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - //------------------------------------------------------------------ - // Process Control - //------------------------------------------------------------------ - lldb_private::Status WillResume() override; - - lldb_private::Status DoResume() override; - - lldb_private::Status DoHalt(bool &caused_stop) override; - - lldb_private::Status DoDetach(bool keep_stopped) override; - - lldb_private::Status DoSignal(int signal) override; - - lldb_private::Status DoDestroy() override; - - void RefreshStateAfterStop() override; - - //------------------------------------------------------------------ - // Process Queries - //------------------------------------------------------------------ - bool IsAlive() override; - - //------------------------------------------------------------------ - // Process Memory - //------------------------------------------------------------------ - size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - lldb_private::Status &error) override; - - size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, - lldb_private::Status &error) override; - - lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, - lldb_private::Status &error) override; - - lldb_private::Status DoDeallocateMemory(lldb::addr_t ptr) override; - - //---------------------------------------------------------------------- - // Process Breakpoints - //---------------------------------------------------------------------- - lldb_private::Status - EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - lldb_private::Status - DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override; - - //---------------------------------------------------------------------- - // Process Watchpoints - //---------------------------------------------------------------------- - lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - - lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp, - bool notify = true) override; - - CommunicationKDP &GetCommunication() { return m_comm; } - -protected: - friend class ThreadKDP; - friend class CommunicationKDP; - - //---------------------------------------------------------------------- - // Accessors - //---------------------------------------------------------------------- - bool IsRunning(lldb::StateType state) { - return state == lldb::eStateRunning || IsStepping(state); - } - - bool IsStepping(lldb::StateType state) { - return state == lldb::eStateStepping; - } - - bool CanResume(lldb::StateType state) { return state == lldb::eStateStopped; } - - bool HasExited(lldb::StateType state) { return state == lldb::eStateExited; } - - bool GetHostArchitecture(lldb_private::ArchSpec &arch); - - bool ProcessIDIsValid() const; - - void Clear(); - - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; - - enum { - eBroadcastBitAsyncContinue = (1 << 0), - eBroadcastBitAsyncThreadShouldExit = (1 << 1) - }; - - lldb::ThreadSP GetKernelThread(); - - //------------------------------------------------------------------ - /// Broadcaster event bits definitions. - //------------------------------------------------------------------ - CommunicationKDP m_comm; - lldb_private::Broadcaster m_async_broadcaster; - lldb_private::HostThread m_async_thread; - lldb_private::ConstString m_dyld_plugin_name; - lldb::addr_t m_kernel_load_addr; - lldb::CommandObjectSP m_command_sp; - lldb::ThreadWP m_kernel_thread_wp; - - bool StartAsyncThread(); - - void StopAsyncThread(); - - static void *AsyncThread(void *arg); - -private: - //------------------------------------------------------------------ - // For ProcessKDP only - //------------------------------------------------------------------ - - DISALLOW_COPY_AND_ASSIGN(ProcessKDP); -}; - -#endif // liblldb_ProcessKDP_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp deleted file mode 100644 index ffab3e5e23c77..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===-- ProcessKDPLog.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ProcessKDPLog.h" - -using namespace lldb_private; - -static constexpr Log::Category g_categories[] = { - {{"async"}, {"log asynchronous activity"}, KDP_LOG_ASYNC}, - {{"break"}, {"log breakpoints"}, KDP_LOG_BREAKPOINTS}, - {{"comm"}, {"log communication activity"}, KDP_LOG_COMM}, - {{"data-long"}, - {"log memory bytes for memory reads and writes for all transactions"}, - KDP_LOG_MEMORY_DATA_LONG}, - {{"data-short"}, - {"log memory bytes for memory reads and writes for short transactions " - "only"}, - KDP_LOG_MEMORY_DATA_SHORT}, - {{"memory"}, {"log memory reads and writes"}, KDP_LOG_MEMORY}, - {{"packets"}, {"log gdb remote packets"}, KDP_LOG_PACKETS}, - {{"process"}, {"log process events and activities"}, KDP_LOG_PROCESS}, - {{"step"}, {"log step related activities"}, KDP_LOG_STEP}, - {{"thread"}, {"log thread events and activities"}, KDP_LOG_THREAD}, - {{"watch"}, {"log watchpoint related activities"}, KDP_LOG_WATCHPOINTS}, -}; - -Log::Channel ProcessKDPLog::g_channel(g_categories, KDP_LOG_DEFAULT); - -void ProcessKDPLog::Initialize() { Log::Register("kdp-remote", g_channel); } diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h deleted file mode 100644 index 908754ec992b1..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h +++ /dev/null @@ -1,43 +0,0 @@ -//===-- ProcessKDPLog.h -----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessKDPLog_h_ -#define liblldb_ProcessKDPLog_h_ - -#include "lldb/Utility/Log.h" - -#define KDP_LOG_PROCESS (1u << 1) -#define KDP_LOG_THREAD (1u << 2) -#define KDP_LOG_PACKETS (1u << 3) -#define KDP_LOG_MEMORY (1u << 4) // Log memory reads/writes calls -#define KDP_LOG_MEMORY_DATA_SHORT \ - (1u << 5) // Log short memory reads/writes bytes -#define KDP_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes -#define KDP_LOG_BREAKPOINTS (1u << 7) -#define KDP_LOG_WATCHPOINTS (1u << 8) -#define KDP_LOG_STEP (1u << 9) -#define KDP_LOG_COMM (1u << 10) -#define KDP_LOG_ASYNC (1u << 11) -#define KDP_LOG_ALL (UINT32_MAX) -#define KDP_LOG_DEFAULT KDP_LOG_PACKETS - -namespace lldb_private { -class ProcessKDPLog { - static Log::Channel g_channel; - -public: - static void Initialize(); - - static Log *GetLogIfAllCategoriesSet(uint32_t mask) { - return g_channel.GetLogIfAll(mask); - } -}; -} - -#endif // liblldb_ProcessKDPLog_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp deleted file mode 100644 index 0f9e62ce355a0..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//===-- RegisterContextKDP_arm.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "RegisterContextKDP_arm.h" - -#include "ProcessKDP.h" -#include "ThreadKDP.h" - -using namespace lldb; -using namespace lldb_private; - -RegisterContextKDP_arm::RegisterContextKDP_arm(ThreadKDP &thread, - uint32_t concrete_frame_idx) - : RegisterContextDarwin_arm(thread, concrete_frame_idx), - m_kdp_thread(thread) {} - -RegisterContextKDP_arm::~RegisterContextKDP_arm() {} - -int RegisterContextKDP_arm::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, DBGRegSet, &dbg, sizeof(dbg), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoWriteGPR(lldb::tid_t tid, int flavor, - const GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoWriteFPU(lldb::tid_t tid, int flavor, - const FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoWriteEXC(lldb::tid_t tid, int flavor, - const EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm::DoWriteDBG(lldb::tid_t tid, int flavor, - const DBG &dbg) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, DBGRegSet, &dbg, sizeof(dbg), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h deleted file mode 100644 index 1532f23207f42..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h +++ /dev/null @@ -1,44 +0,0 @@ -//===-- RegisterContextKDP_arm.h --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextKDP_arm_h_ -#define liblldb_RegisterContextKDP_arm_h_ - - -#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" - -class ThreadKDP; - -class RegisterContextKDP_arm : public RegisterContextDarwin_arm { -public: - RegisterContextKDP_arm(ThreadKDP &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextKDP_arm(); - -protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); - - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); - - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); - - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); - - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); - - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); - - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); - - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); - - ThreadKDP &m_kdp_thread; -}; - -#endif // liblldb_RegisterContextKDP_arm_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp deleted file mode 100644 index e13a7f3ad9079..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//===-- RegisterContextKDP_arm64.cpp ------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "RegisterContextKDP_arm64.h" - -#include "ProcessKDP.h" -#include "ThreadKDP.h" - -using namespace lldb; -using namespace lldb_private; - -RegisterContextKDP_arm64::RegisterContextKDP_arm64(ThreadKDP &thread, - uint32_t concrete_frame_idx) - : RegisterContextDarwin_arm64(thread, concrete_frame_idx), - m_kdp_thread(thread) {} - -RegisterContextKDP_arm64::~RegisterContextKDP_arm64() {} - -int RegisterContextKDP_arm64::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, DBGRegSet, &dbg, sizeof(dbg), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoWriteGPR(lldb::tid_t tid, int flavor, - const GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoWriteFPU(lldb::tid_t tid, int flavor, - const FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoWriteEXC(lldb::tid_t tid, int flavor, - const EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_arm64::DoWriteDBG(lldb::tid_t tid, int flavor, - const DBG &dbg) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, DBGRegSet, &dbg, sizeof(dbg), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h deleted file mode 100644 index be4038ba96eaf..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h +++ /dev/null @@ -1,45 +0,0 @@ -//===-- RegisterContextKDP_arm64.h --------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextKDP_arm64_h_ -#define liblldb_RegisterContextKDP_arm64_h_ - - -#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" - -class ThreadKDP; - -class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64 { -public: - RegisterContextKDP_arm64(ThreadKDP &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextKDP_arm64(); - -protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); - - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); - - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); - - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); - - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); - - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); - - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); - - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); - - ThreadKDP &m_kdp_thread; -}; - -#endif // liblldb_RegisterContextKDP_arm64_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp deleted file mode 100644 index 096aa0f95d009..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//===-- RegisterContextKDP_i386.cpp -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "RegisterContextKDP_i386.h" -#include "ProcessKDP.h" -#include "ThreadKDP.h" - -using namespace lldb; -using namespace lldb_private; - -RegisterContextKDP_i386::RegisterContextKDP_i386(ThreadKDP &thread, - uint32_t concrete_frame_idx) - : RegisterContextDarwin_i386(thread, concrete_frame_idx), - m_kdp_thread(thread) {} - -RegisterContextKDP_i386::~RegisterContextKDP_i386() {} - -int RegisterContextKDP_i386::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_i386::DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_i386::DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_i386::DoWriteGPR(lldb::tid_t tid, int flavor, - const GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_i386::DoWriteFPU(lldb::tid_t tid, int flavor, - const FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_i386::DoWriteEXC(lldb::tid_t tid, int flavor, - const EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h deleted file mode 100644 index 699d5fabe1570..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h +++ /dev/null @@ -1,39 +0,0 @@ -//===-- RegisterContextKDP_i386.h -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextKDP_i386_h_ -#define liblldb_RegisterContextKDP_i386_h_ - -#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" - -class ThreadKDP; - -class RegisterContextKDP_i386 : public RegisterContextDarwin_i386 { -public: - RegisterContextKDP_i386(ThreadKDP &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextKDP_i386(); - -protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); - - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); - - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); - - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); - - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); - - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); - - ThreadKDP &m_kdp_thread; -}; - -#endif // liblldb_RegisterContextKDP_i386_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp deleted file mode 100644 index 9d85145f2eaf2..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp +++ /dev/null @@ -1,118 +0,0 @@ -//===-- RegisterContextKDP_x86_64.cpp ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "RegisterContextKDP_x86_64.h" -#include "ProcessKDP.h" -#include "ThreadKDP.h" - -using namespace lldb; -using namespace lldb_private; - -RegisterContextKDP_x86_64::RegisterContextKDP_x86_64( - ThreadKDP &thread, uint32_t concrete_frame_idx) - : RegisterContextDarwin_x86_64(thread, concrete_frame_idx), - m_kdp_thread(thread) {} - -RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64() {} - -int RegisterContextKDP_x86_64::DoReadGPR(lldb::tid_t tid, int flavor, - GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_x86_64::DoReadFPU(lldb::tid_t tid, int flavor, - FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_x86_64::DoReadEXC(lldb::tid_t tid, int flavor, - EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestReadRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_x86_64::DoWriteGPR(lldb::tid_t tid, int flavor, - const GPR &gpr) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, GPRRegSet, &gpr, sizeof(gpr), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_x86_64::DoWriteFPU(lldb::tid_t tid, int flavor, - const FPU &fpu) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, FPURegSet, &fpu, sizeof(fpu), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} - -int RegisterContextKDP_x86_64::DoWriteEXC(lldb::tid_t tid, int flavor, - const EXC &exc) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - Status error; - if (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .SendRequestWriteRegisters(tid, EXCRegSet, &exc, sizeof(exc), - error)) { - if (error.Success()) - return 0; - } - } - return -1; -} diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h deleted file mode 100644 index 9841ad77b0044..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h +++ /dev/null @@ -1,39 +0,0 @@ -//===-- RegisterContextKDP_x86_64.h -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextKDP_x86_64_h_ -#define liblldb_RegisterContextKDP_x86_64_h_ - -#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" - -class ThreadKDP; - -class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64 { -public: - RegisterContextKDP_x86_64(ThreadKDP &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextKDP_x86_64(); - -protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); - - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); - - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); - - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); - - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); - - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); - - ThreadKDP &m_kdp_thread; -}; - -#endif // liblldb_RegisterContextKDP_x86_64_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp deleted file mode 100644 index 6f26acd0b8aa7..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ /dev/null @@ -1,170 +0,0 @@ -//===-- ThreadKDP.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ThreadKDP.h" - -#include "lldb/Host/SafeMachO.h" - -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Unwind.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/StreamString.h" - -#include "Plugins/Process/Utility/StopInfoMachException.h" -#include "ProcessKDP.h" -#include "ProcessKDPLog.h" -#include "RegisterContextKDP_arm.h" -#include "RegisterContextKDP_arm64.h" -#include "RegisterContextKDP_i386.h" -#include "RegisterContextKDP_x86_64.h" - -using namespace lldb; -using namespace lldb_private; - -//---------------------------------------------------------------------- -// Thread Registers -//---------------------------------------------------------------------- - -ThreadKDP::ThreadKDP(Process &process, lldb::tid_t tid) - : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(), - m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS) { - Log *log = ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD); - LLDB_LOG(log, "this = {0}, tid = {1:x}", this, GetID()); -} - -ThreadKDP::~ThreadKDP() { - Log *log = ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD); - LLDB_LOG(log, "this = {0}, tid = {1:x}", this, GetID()); - DestroyThread(); -} - -const char *ThreadKDP::GetName() { - if (m_thread_name.empty()) - return nullptr; - return m_thread_name.c_str(); -} - -const char *ThreadKDP::GetQueueName() { return nullptr; } - -void ThreadKDP::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. - const bool force = false; - lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); - if (reg_ctx_sp) - reg_ctx_sp->InvalidateIfNeeded(force); -} - -bool ThreadKDP::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } - -void ThreadKDP::Dump(Log *log, uint32_t index) {} - -bool ThreadKDP::ShouldStop(bool &step_more) { return true; } -lldb::RegisterContextSP ThreadKDP::GetRegisterContext() { - if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrame(nullptr); - return m_reg_context_sp; -} - -lldb::RegisterContextSP -ThreadKDP::CreateRegisterContextForFrame(StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) { - ProcessSP process_sp(CalculateProcess()); - if (process_sp) { - switch (static_cast<ProcessKDP *>(process_sp.get()) - ->GetCommunication() - .GetCPUType()) { - case llvm::MachO::CPU_TYPE_ARM: - reg_ctx_sp.reset(new RegisterContextKDP_arm(*this, concrete_frame_idx)); - break; - case llvm::MachO::CPU_TYPE_ARM64: - reg_ctx_sp.reset( - new RegisterContextKDP_arm64(*this, concrete_frame_idx)); - break; - case llvm::MachO::CPU_TYPE_I386: - reg_ctx_sp.reset( - new RegisterContextKDP_i386(*this, concrete_frame_idx)); - break; - case llvm::MachO::CPU_TYPE_X86_64: - reg_ctx_sp.reset( - new RegisterContextKDP_x86_64(*this, concrete_frame_idx)); - break; - default: - llvm_unreachable("Add CPU type support in KDP"); - } - } - } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); - } - return reg_ctx_sp; -} - -bool ThreadKDP::CalculateStopInfo() { - ProcessSP process_sp(GetProcess()); - if (process_sp) { - if (m_cached_stop_info_sp) { - SetStopInfo(m_cached_stop_info_sp); - } else { - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP)); - } - return true; - } - return false; -} - -void ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION( - const DataExtractor &exc_reply_packet) { - lldb::offset_t offset = 0; - uint8_t reply_command = exc_reply_packet.GetU8(&offset); - if (reply_command == CommunicationKDP::KDP_EXCEPTION) { - offset = 8; - const uint32_t count = exc_reply_packet.GetU32(&offset); - if (count >= 1) { - // const uint32_t cpu = exc_reply_packet.GetU32 (&offset); - offset += 4; // Skip the useless CPU field - const uint32_t exc_type = exc_reply_packet.GetU32(&offset); - const uint32_t exc_code = exc_reply_packet.GetU32(&offset); - const uint32_t exc_subcode = exc_reply_packet.GetU32(&offset); - // We have to make a copy of the stop info because the thread list will - // iterate through the threads and clear all stop infos.. - - // Let the StopInfoMachException::CreateStopReasonWithMachException() - // function update the PC if needed as we might hit a software breakpoint - // and need to decrement the PC (i386 and x86_64 need this) and KDP - // doesn't do this for us. - const bool pc_already_adjusted = false; - const bool adjust_pc_if_needed = true; - - m_cached_stop_info_sp = - StopInfoMachException::CreateStopReasonWithMachException( - *this, exc_type, 2, exc_code, exc_subcode, 0, pc_already_adjusted, - adjust_pc_if_needed); - } - } -} diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h deleted file mode 100644 index ea517b4254fc9..0000000000000 --- a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h +++ /dev/null @@ -1,77 +0,0 @@ -//===-- ThreadKDP.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ThreadKDP_h_ -#define liblldb_ThreadKDP_h_ - -#include <string> - -#include "lldb/Target/Process.h" -#include "lldb/Target/Thread.h" - -class ProcessKDP; - -class ThreadKDP : public lldb_private::Thread { -public: - ThreadKDP(lldb_private::Process &process, lldb::tid_t tid); - - virtual ~ThreadKDP(); - - virtual void RefreshStateAfterStop(); - - virtual const char *GetName(); - - virtual const char *GetQueueName(); - - virtual lldb::RegisterContextSP GetRegisterContext(); - - virtual lldb::RegisterContextSP - CreateRegisterContextForFrame(lldb_private::StackFrame *frame); - - void Dump(lldb_private::Log *log, uint32_t index); - - static bool ThreadIDIsValid(lldb::tid_t thread); - - bool ShouldStop(bool &step_more); - - const char *GetBasicInfoAsString(); - - void SetName(const char *name) { - if (name && name[0]) - m_thread_name.assign(name); - else - m_thread_name.clear(); - } - - lldb::addr_t GetThreadDispatchQAddr() { return m_thread_dispatch_qaddr; } - - void SetThreadDispatchQAddr(lldb::addr_t thread_dispatch_qaddr) { - m_thread_dispatch_qaddr = thread_dispatch_qaddr; - } - - void SetStopInfoFrom_KDP_EXCEPTION( - const lldb_private::DataExtractor &exc_reply_packet); - -protected: - friend class ProcessKDP; - - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - std::string m_thread_name; - std::string m_dispatch_queue_name; - lldb::addr_t m_thread_dispatch_qaddr; - lldb::StopInfoSP m_cached_stop_info_sp; - //------------------------------------------------------------------ - // Protected member functions. - //------------------------------------------------------------------ - virtual bool CalculateStopInfo(); -}; - -#endif // liblldb_ThreadKDP_h_ diff --git a/source/Plugins/Process/NetBSD/CMakeLists.txt b/source/Plugins/Process/NetBSD/CMakeLists.txt deleted file mode 100644 index e131e6d70468b..0000000000000 --- a/source/Plugins/Process/NetBSD/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -add_lldb_library(lldbPluginProcessNetBSD PLUGIN - NativeProcessNetBSD.cpp - NativeRegisterContextNetBSD.cpp - NativeRegisterContextNetBSD_x86_64.cpp - NativeThreadNetBSD.cpp - - LINK_LIBS - lldbHost - lldbSymbol - lldbTarget - lldbUtility - lldbPluginProcessPOSIX - lldbPluginProcessUtility - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/POSIX/CMakeLists.txt b/source/Plugins/Process/POSIX/CMakeLists.txt deleted file mode 100644 index f058e01c74394..0000000000000 --- a/source/Plugins/Process/POSIX/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_lldb_library(lldbPluginProcessPOSIX PLUGIN - CrashReason.cpp - ProcessMessage.cpp - ProcessPOSIXLog.cpp - - LINK_LIBS - lldbInterpreter - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/Utility/CMakeLists.txt b/source/Plugins/Process/Utility/CMakeLists.txt deleted file mode 100644 index e36ce4dec98a8..0000000000000 --- a/source/Plugins/Process/Utility/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -add_lldb_library(lldbPluginProcessUtility PLUGIN - DynamicRegisterInfo.cpp - FreeBSDSignals.cpp - GDBRemoteSignals.cpp - HistoryThread.cpp - HistoryUnwind.cpp - InferiorCallPOSIX.cpp - LinuxProcMaps.cpp - LinuxSignals.cpp - MipsLinuxSignals.cpp - NativeRegisterContextRegisterInfo.cpp - NetBSDSignals.cpp - RegisterContextDarwin_arm.cpp - RegisterContextDarwin_arm64.cpp - RegisterContextDarwin_i386.cpp - RegisterContextDarwin_x86_64.cpp - RegisterContextDummy.cpp - RegisterContextFreeBSD_i386.cpp - RegisterContextFreeBSD_mips64.cpp - RegisterContextFreeBSD_powerpc.cpp - RegisterContextFreeBSD_x86_64.cpp - RegisterContextHistory.cpp - RegisterContextLinux_i386.cpp - RegisterContextLinux_x86_64.cpp - RegisterContextLinux_mips64.cpp - RegisterContextLinux_mips.cpp - RegisterContextLinux_s390x.cpp - RegisterContextLLDB.cpp - RegisterContextMacOSXFrameBackchain.cpp - RegisterContextMach_arm.cpp - RegisterContextMach_i386.cpp - RegisterContextMach_x86_64.cpp - RegisterContextMemory.cpp - RegisterContextNetBSD_x86_64.cpp - RegisterContextOpenBSD_i386.cpp - RegisterContextOpenBSD_x86_64.cpp - RegisterContextPOSIX_arm.cpp - RegisterContextPOSIX_arm64.cpp - RegisterContextPOSIX_mips64.cpp - RegisterContextPOSIX_powerpc.cpp - RegisterContextPOSIX_ppc64le.cpp - RegisterContextPOSIX_s390x.cpp - RegisterContextPOSIX_x86.cpp - RegisterContextThreadMemory.cpp - RegisterInfoPOSIX_arm.cpp - RegisterInfoPOSIX_arm64.cpp - RegisterInfoPOSIX_ppc64le.cpp - StopInfoMachException.cpp - ThreadMemory.cpp - UnwindLLDB.cpp - UnwindMacOSXFrameBackchain.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbDataFormatters - lldbExpression - lldbHost - lldbSymbol - lldbTarget - lldbUtility - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/Windows/Common/CMakeLists.txt b/source/Plugins/Process/Windows/Common/CMakeLists.txt deleted file mode 100644 index 0926290861833..0000000000000 --- a/source/Plugins/Process/Windows/Common/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -set(PROC_WINDOWS_COMMON_SOURCES - DebuggerThread.cpp - LocalDebugDelegate.cpp - ProcessWindows.cpp - ProcessWindowsLog.cpp - RegisterContextWindows.cpp - TargetThreadWindows.cpp - ) - -if (CMAKE_SIZEOF_VOID_P EQUAL 4) - set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES} - x86/RegisterContextWindows_x86.cpp - ) -elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(PROC_WINDOWS_COMMON_SOURCES ${PROC_WINDOWS_COMMON_SOURCES} - x64/RegisterContextWindows_x64.cpp - ) -endif() - -add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN - ${PROC_WINDOWS_COMMON_SOURCES} - - LINK_LIBS - lldbCore - lldbHost - lldbInterpreter - lldbSymbol - lldbTarget - ws2_32 - rpcrt4 - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/source/Plugins/Process/Windows/Common/DebuggerThread.cpp deleted file mode 100644 index 81ec25871c577..0000000000000 --- a/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ /dev/null @@ -1,520 +0,0 @@ -//===-- DebuggerThread.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DebuggerThread.h" -#include "ExceptionRecord.h" -#include "IDebugDelegate.h" - -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/windows/HostProcessWindows.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/ProcessLauncherWindows.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Predicate.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Windows/Common/ProcessWindowsLog.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { -struct DebugLaunchContext { - DebugLaunchContext(DebuggerThread *thread, - const ProcessLaunchInfo &launch_info) - : m_thread(thread), m_launch_info(launch_info) {} - DebuggerThread *m_thread; - ProcessLaunchInfo m_launch_info; -}; - -struct DebugAttachContext { - DebugAttachContext(DebuggerThread *thread, lldb::pid_t pid, - const ProcessAttachInfo &attach_info) - : m_thread(thread), m_pid(pid), m_attach_info(attach_info) {} - DebuggerThread *m_thread; - lldb::pid_t m_pid; - ProcessAttachInfo m_attach_info; -}; -} // namespace - -DebuggerThread::DebuggerThread(DebugDelegateSP debug_delegate) - : m_debug_delegate(debug_delegate), m_pid_to_detach(0), - m_is_shutting_down(false) { - m_debugging_ended_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); -} - -DebuggerThread::~DebuggerThread() { ::CloseHandle(m_debugging_ended_event); } - -Status DebuggerThread::DebugLaunch(const ProcessLaunchInfo &launch_info) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "launching '{0}'", launch_info.GetExecutableFile().GetPath()); - - Status error; - DebugLaunchContext *context = new DebugLaunchContext(this, launch_info); - HostThread slave_thread(ThreadLauncher::LaunchThread( - "lldb.plugin.process-windows.slave[?]", DebuggerThreadLaunchRoutine, - context, &error)); - - if (!error.Success()) - LLDB_LOG(log, "couldn't launch debugger thread. {0}", error); - - return error; -} - -Status DebuggerThread::DebugAttach(lldb::pid_t pid, - const ProcessAttachInfo &attach_info) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "attaching to '{0}'", pid); - - Status error; - DebugAttachContext *context = new DebugAttachContext(this, pid, attach_info); - HostThread slave_thread(ThreadLauncher::LaunchThread( - "lldb.plugin.process-windows.slave[?]", DebuggerThreadAttachRoutine, - context, &error)); - - if (!error.Success()) - LLDB_LOG(log, "couldn't attach to process '{0}'. {1}", pid, error); - - return error; -} - -lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine(void *data) { - DebugLaunchContext *context = static_cast<DebugLaunchContext *>(data); - lldb::thread_result_t result = - context->m_thread->DebuggerThreadLaunchRoutine(context->m_launch_info); - delete context; - return result; -} - -lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine(void *data) { - DebugAttachContext *context = static_cast<DebugAttachContext *>(data); - lldb::thread_result_t result = context->m_thread->DebuggerThreadAttachRoutine( - context->m_pid, context->m_attach_info); - delete context; - return result; -} - -lldb::thread_result_t DebuggerThread::DebuggerThreadLaunchRoutine( - const ProcessLaunchInfo &launch_info) { - // Grab a shared_ptr reference to this so that we know it won't get deleted - // until after the thread routine has exited. - std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "preparing to launch '{0}' on background thread.", - launch_info.GetExecutableFile().GetPath()); - - Status error; - ProcessLauncherWindows launcher; - HostProcess process(launcher.LaunchProcess(launch_info, error)); - // If we couldn't create the process, notify waiters immediately. Otherwise - // enter the debug loop and wait until we get the create process debug - // notification. Note that if the process was created successfully, we can - // throw away the process handle we got from CreateProcess because Windows - // will give us another (potentially more useful?) handle when it sends us - // the CREATE_PROCESS_DEBUG_EVENT. - if (error.Success()) - DebugLoop(); - else - m_debug_delegate->OnDebuggerError(error, 0); - - return 0; -} - -lldb::thread_result_t DebuggerThread::DebuggerThreadAttachRoutine( - lldb::pid_t pid, const ProcessAttachInfo &attach_info) { - // Grab a shared_ptr reference to this so that we know it won't get deleted - // until after the thread routine has exited. - std::shared_ptr<DebuggerThread> this_ref(shared_from_this()); - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "preparing to attach to process '{0}' on background thread.", - pid); - - if (!DebugActiveProcess((DWORD)pid)) { - Status error(::GetLastError(), eErrorTypeWin32); - m_debug_delegate->OnDebuggerError(error, 0); - return 0; - } - - // The attach was successful, enter the debug loop. From here on out, this - // is no different than a create process operation, so all the same comments - // in DebugLaunch should apply from this point out. - DebugLoop(); - - return 0; -} - -Status DebuggerThread::StopDebugging(bool terminate) { - Status error; - - lldb::pid_t pid = m_process.GetProcessId(); - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "terminate = {0}, inferior={1}.", terminate, pid); - - // Set m_is_shutting_down to true if it was false. Return if it was already - // true. - bool expected = false; - if (!m_is_shutting_down.compare_exchange_strong(expected, true)) - return error; - - // Make a copy of the process, since the termination sequence will reset - // DebuggerThread's internal copy and it needs to remain open for the Wait - // operation. - HostProcess process_copy = m_process; - lldb::process_t handle = m_process.GetNativeProcess().GetSystemHandle(); - - if (terminate) { - if (handle != nullptr && handle != LLDB_INVALID_PROCESS) { - // Initiate the termination before continuing the exception, so that the - // next debug event we get is the exit process event, and not some other - // event. - BOOL terminate_suceeded = TerminateProcess(handle, 0); - LLDB_LOG(log, - "calling TerminateProcess({0}, 0) (inferior={1}), success={2}", - handle, pid, terminate_suceeded); - } else { - LLDB_LOG(log, - "NOT calling TerminateProcess because the inferior is not valid " - "({0}, 0) (inferior={1})", - handle, pid); - } - } - - // If we're stuck waiting for an exception to continue (e.g. the user is at a - // breakpoint messing around in the debugger), continue it now. But only - // AFTER calling TerminateProcess to make sure that the very next call to - // WaitForDebugEvent is an exit process event. - if (m_active_exception.get()) { - LLDB_LOG(log, "masking active exception"); - ContinueAsyncException(ExceptionResult::MaskException); - } - - if (!terminate) { - // Indicate that we want to detach. - m_pid_to_detach = GetProcess().GetProcessId(); - - // Force a fresh break so that the detach can happen from the debugger - // thread. - if (!::DebugBreakProcess( - GetProcess().GetNativeProcess().GetSystemHandle())) { - error.SetError(::GetLastError(), eErrorTypeWin32); - } - } - - LLDB_LOG(log, "waiting for detach from process {0} to complete.", pid); - - DWORD wait_result = WaitForSingleObject(m_debugging_ended_event, 5000); - if (wait_result != WAIT_OBJECT_0) { - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "error: WaitForSingleObject({0}, 5000) returned {1}", - m_debugging_ended_event, wait_result); - } else - LLDB_LOG(log, "detach from process {0} completed successfully.", pid); - - if (!error.Success()) { - LLDB_LOG(log, "encountered an error while trying to stop process {0}. {1}", - pid, error); - } - return error; -} - -void DebuggerThread::ContinueAsyncException(ExceptionResult result) { - if (!m_active_exception.get()) - return; - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS | - WINDOWS_LOG_EXCEPTION); - LLDB_LOG(log, "broadcasting for inferior process {0}.", - m_process.GetProcessId()); - - m_active_exception.reset(); - m_exception_pred.SetValue(result, eBroadcastAlways); -} - -void DebuggerThread::FreeProcessHandles() { - m_process = HostProcess(); - m_main_thread = HostThread(); - if (m_image_file) { - ::CloseHandle(m_image_file); - m_image_file = nullptr; - } -} - -void DebuggerThread::DebugLoop() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT); - DEBUG_EVENT dbe = {}; - bool should_debug = true; - LLDB_LOGV(log, "Entering WaitForDebugEvent loop"); - while (should_debug) { - LLDB_LOGV(log, "Calling WaitForDebugEvent"); - BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE); - if (wait_result) { - DWORD continue_status = DBG_CONTINUE; - switch (dbe.dwDebugEventCode) { - default: - llvm_unreachable("Unhandle debug event code!"); - case EXCEPTION_DEBUG_EVENT: { - ExceptionResult status = - HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId); - - if (status == ExceptionResult::MaskException) - continue_status = DBG_CONTINUE; - else if (status == ExceptionResult::SendToApplication) - continue_status = DBG_EXCEPTION_NOT_HANDLED; - - break; - } - case CREATE_THREAD_DEBUG_EVENT: - continue_status = - HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId); - break; - case CREATE_PROCESS_DEBUG_EVENT: - continue_status = - HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId); - break; - case EXIT_THREAD_DEBUG_EVENT: - continue_status = - HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId); - break; - case EXIT_PROCESS_DEBUG_EVENT: - continue_status = - HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId); - should_debug = false; - break; - case LOAD_DLL_DEBUG_EVENT: - continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId); - break; - case UNLOAD_DLL_DEBUG_EVENT: - continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId); - break; - case OUTPUT_DEBUG_STRING_EVENT: - continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId); - break; - case RIP_EVENT: - continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId); - if (dbe.u.RipInfo.dwType == SLE_ERROR) - should_debug = false; - break; - } - - LLDB_LOGV(log, "calling ContinueDebugEvent({0}, {1}, {2}) on thread {3}.", - dbe.dwProcessId, dbe.dwThreadId, continue_status, - ::GetCurrentThreadId()); - - ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status); - - if (m_detached) { - should_debug = false; - } - } else { - LLDB_LOG(log, "returned FALSE from WaitForDebugEvent. Error = {0}", - ::GetLastError()); - - should_debug = false; - } - } - FreeProcessHandles(); - - LLDB_LOG(log, "WaitForDebugEvent loop completed, exiting."); - ::SetEvent(m_debugging_ended_event); -} - -ExceptionResult -DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = - ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_EXCEPTION); - if (m_is_shutting_down) { - // A breakpoint that occurs while `m_pid_to_detach` is non-zero is a magic - // exception that - // we use simply to wake up the DebuggerThread so that we can close out the - // debug loop. - if (m_pid_to_detach != 0 && - info.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { - LLDB_LOG(log, "Breakpoint exception is cue to detach from process {0:x}", - m_pid_to_detach.load()); - ::DebugActiveProcessStop(m_pid_to_detach); - m_detached = true; - } - - // Don't perform any blocking operations while we're shutting down. That - // will cause TerminateProcess -> WaitForSingleObject to time out. - return ExceptionResult::SendToApplication; - } - - bool first_chance = (info.dwFirstChance != 0); - - m_active_exception.reset( - new ExceptionRecord(info.ExceptionRecord, thread_id)); - LLDB_LOG(log, "encountered {0} chance exception {1:x} on thread {2:x}", - first_chance ? "first" : "second", - info.ExceptionRecord.ExceptionCode, thread_id); - - ExceptionResult result = - m_debug_delegate->OnDebugException(first_chance, *m_active_exception); - m_exception_pred.SetValue(result, eBroadcastNever); - - LLDB_LOG(log, "waiting for ExceptionPred != BreakInDebugger"); - result = *m_exception_pred.WaitForValueNotEqualTo( - ExceptionResult::BreakInDebugger); - - LLDB_LOG(log, "got ExceptionPred = {0}", (int)m_exception_pred.GetValue()); - return result; -} - -DWORD -DebuggerThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = - ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_THREAD); - LLDB_LOG(log, "Thread {0} spawned in process {1}", thread_id, - m_process.GetProcessId()); - HostThread thread(info.hThread); - thread.GetNativeThread().SetOwnsHandle(false); - m_debug_delegate->OnCreateThread(thread); - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = - ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_PROCESS); - uint32_t process_id = ::GetProcessId(info.hProcess); - - LLDB_LOG(log, "process {0} spawned", process_id); - - std::string thread_name; - llvm::raw_string_ostream name_stream(thread_name); - name_stream << "lldb.plugin.process-windows.slave[" << process_id << "]"; - name_stream.flush(); - llvm::set_thread_name(thread_name); - - // info.hProcess and info.hThread are closed automatically by Windows when - // EXIT_PROCESS_DEBUG_EVENT is received. - m_process = HostProcess(info.hProcess); - ((HostProcessWindows &)m_process.GetNativeProcess()).SetOwnsHandle(false); - m_main_thread = HostThread(info.hThread); - m_main_thread.GetNativeThread().SetOwnsHandle(false); - m_image_file = info.hFile; - - lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfImage); - m_debug_delegate->OnDebuggerConnected(load_addr); - - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = - ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_THREAD); - LLDB_LOG(log, "Thread {0} exited with code {1} in process {2}", thread_id, - info.dwExitCode, m_process.GetProcessId()); - m_debug_delegate->OnExitThread(thread_id, info.dwExitCode); - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = - ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT | WINDOWS_LOG_THREAD); - LLDB_LOG(log, "process {0} exited with code {1}", m_process.GetProcessId(), - info.dwExitCode); - - m_debug_delegate->OnExitProcess(info.dwExitCode); - - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT); - if (info.hFile == nullptr) { - // Not sure what this is, so just ignore it. - LLDB_LOG(log, "Warning: Inferior {0} has a NULL file handle, returning...", - m_process.GetProcessId()); - return DBG_CONTINUE; - } - - std::vector<wchar_t> buffer(1); - DWORD required_size = - GetFinalPathNameByHandleW(info.hFile, &buffer[0], 0, VOLUME_NAME_DOS); - if (required_size > 0) { - buffer.resize(required_size + 1); - required_size = GetFinalPathNameByHandleW(info.hFile, &buffer[0], - required_size, VOLUME_NAME_DOS); - std::string path_str_utf8; - llvm::convertWideToUTF8(buffer.data(), path_str_utf8); - llvm::StringRef path_str = path_str_utf8; - const char *path = path_str.data(); - if (path_str.startswith("\\\\?\\")) - path += 4; - - FileSpec file_spec(path); - ModuleSpec module_spec(file_spec); - lldb::addr_t load_addr = reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll); - - LLDB_LOG(log, "Inferior {0} - DLL '{1}' loaded at address {2:x}...", - m_process.GetProcessId(), path, info.lpBaseOfDll); - - m_debug_delegate->OnLoadDll(module_spec, load_addr); - } else { - LLDB_LOG( - log, - "Inferior {0} - Error {1} occurred calling GetFinalPathNameByHandle", - m_process.GetProcessId(), ::GetLastError()); - } - // Windows does not automatically close info.hFile, so we need to do it. - ::CloseHandle(info.hFile); - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, - DWORD thread_id) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT); - LLDB_LOG(log, "process {0} unloading DLL at addr {1:x}.", - m_process.GetProcessId(), info.lpBaseOfDll); - - m_debug_delegate->OnUnloadDll( - reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll)); - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, - DWORD thread_id) { - return DBG_CONTINUE; -} - -DWORD -DebuggerThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EVENT); - LLDB_LOG(log, "encountered error {0} (type={1}) in process {2} thread {3}", - info.dwError, info.dwType, m_process.GetProcessId(), thread_id); - - Status error(info.dwError, eErrorTypeWin32); - m_debug_delegate->OnDebuggerError(error, info.dwType); - - return DBG_CONTINUE; -} diff --git a/source/Plugins/Process/Windows/Common/DebuggerThread.h b/source/Plugins/Process/Windows/Common/DebuggerThread.h deleted file mode 100644 index 047d3ccb7296b..0000000000000 --- a/source/Plugins/Process/Windows/Common/DebuggerThread.h +++ /dev/null @@ -1,106 +0,0 @@ -//===-- DebuggerThread.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_DebuggerThread_H_ -#define liblldb_Plugins_Process_Windows_DebuggerThread_H_ - -#include <atomic> -#include <memory> - -#include "ForwardDecl.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Utility/Predicate.h" - -namespace lldb_private { - -//---------------------------------------------------------------------- -// DebuggerThread -// -// Debugs a single process, notifying listeners as appropriate when interesting -// things occur. -//---------------------------------------------------------------------- -class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { -public: - DebuggerThread(DebugDelegateSP debug_delegate); - virtual ~DebuggerThread(); - - Status DebugLaunch(const ProcessLaunchInfo &launch_info); - Status DebugAttach(lldb::pid_t pid, const ProcessAttachInfo &attach_info); - - HostProcess GetProcess() const { return m_process; } - HostThread GetMainThread() const { return m_main_thread; } - std::weak_ptr<ExceptionRecord> GetActiveException() { - return m_active_exception; - } - - Status StopDebugging(bool terminate); - - void ContinueAsyncException(ExceptionResult result); - -private: - void FreeProcessHandles(); - void DebugLoop(); - ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id); - DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, - DWORD thread_id); - DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id); - DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id); - - DebugDelegateSP m_debug_delegate; - - HostProcess m_process; // The process being debugged. - HostThread m_main_thread; // The main thread of the inferior. - - // The image file of the process being debugged. - HANDLE m_image_file = nullptr; - - // The current exception waiting to be handled - ExceptionRecordSP m_active_exception; - - // A predicate which gets signalled when an exception is finished processing - // and the debug loop can be continued. - Predicate<ExceptionResult> m_exception_pred; - - // An event which gets signalled by the debugger thread when it exits the - // debugger loop and is detached from the inferior. - HANDLE m_debugging_ended_event = nullptr; - - // Signals the loop to detach from the process (specified by pid). - std::atomic<DWORD> m_pid_to_detach; - - // Signals the debug loop to stop processing certain types of events that - // block shutdown. - std::atomic<bool> m_is_shutting_down; - - // Indicates we've detached from the inferior process and the debug loop can - // exit. - bool m_detached = false; - - static lldb::thread_result_t DebuggerThreadLaunchRoutine(void *data); - lldb::thread_result_t - DebuggerThreadLaunchRoutine(const ProcessLaunchInfo &launch_info); - static lldb::thread_result_t DebuggerThreadAttachRoutine(void *data); - lldb::thread_result_t - DebuggerThreadAttachRoutine(lldb::pid_t pid, - const ProcessAttachInfo &launch_info); -}; -} -#endif diff --git a/source/Plugins/Process/Windows/Common/ExceptionRecord.h b/source/Plugins/Process/Windows/Common/ExceptionRecord.h deleted file mode 100644 index 1eec85d52c264..0000000000000 --- a/source/Plugins/Process/Windows/Common/ExceptionRecord.h +++ /dev/null @@ -1,80 +0,0 @@ -//===-- ExceptionRecord.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_ExceptionRecord_H_ -#define liblldb_Plugins_Process_Windows_ExceptionRecord_H_ - -#include "lldb/Host/windows/windows.h" -#include "lldb/lldb-forward.h" -#include <dbghelp.h> - -#include <memory> -#include <vector> - -namespace lldb_private { - -//---------------------------------------------------------------------- -// ExceptionRecord -// -// ExceptionRecord defines an interface which allows implementors to receive -// notification of events that happen in a debugged process. -//---------------------------------------------------------------------- -class ExceptionRecord { -public: - ExceptionRecord(const EXCEPTION_RECORD &record, lldb::tid_t thread_id) { - m_code = record.ExceptionCode; - m_continuable = (record.ExceptionFlags == 0); - if (record.ExceptionRecord) - m_next_exception.reset( - new ExceptionRecord(*record.ExceptionRecord, thread_id)); - m_exception_addr = reinterpret_cast<lldb::addr_t>(record.ExceptionAddress); - m_thread_id = thread_id; - m_arguments.assign(record.ExceptionInformation, - record.ExceptionInformation + record.NumberParameters); - } - - // MINIDUMP_EXCEPTIONs are almost identical to EXCEPTION_RECORDs. - ExceptionRecord(const MINIDUMP_EXCEPTION &record, lldb::tid_t thread_id) - : m_code(record.ExceptionCode), m_continuable(record.ExceptionFlags == 0), - m_next_exception(nullptr), - m_exception_addr(static_cast<lldb::addr_t>(record.ExceptionAddress)), - m_thread_id(thread_id), - m_arguments(record.ExceptionInformation, - record.ExceptionInformation + record.NumberParameters) { - // Set up link to nested exception. - if (record.ExceptionRecord) { - m_next_exception.reset(new ExceptionRecord( - *reinterpret_cast<const MINIDUMP_EXCEPTION *>(record.ExceptionRecord), - thread_id)); - } - } - - virtual ~ExceptionRecord() {} - - DWORD - GetExceptionCode() const { return m_code; } - bool IsContinuable() const { return m_continuable; } - const ExceptionRecord *GetNextException() const { - return m_next_exception.get(); - } - lldb::addr_t GetExceptionAddress() const { return m_exception_addr; } - - lldb::tid_t GetThreadID() const { return m_thread_id; } - -private: - DWORD m_code; - bool m_continuable; - std::shared_ptr<ExceptionRecord> m_next_exception; - lldb::addr_t m_exception_addr; - lldb::tid_t m_thread_id; - std::vector<ULONG_PTR> m_arguments; -}; -} - -#endif diff --git a/source/Plugins/Process/Windows/Common/ForwardDecl.h b/source/Plugins/Process/Windows/Common/ForwardDecl.h deleted file mode 100644 index ce2af3ca4111a..0000000000000 --- a/source/Plugins/Process/Windows/Common/ForwardDecl.h +++ /dev/null @@ -1,42 +0,0 @@ -//===-- ForwardDecl.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_ForwardDecl_H_ -#define liblldb_Plugins_Process_Windows_ForwardDecl_H_ - -#include <memory> - -// ExceptionResult is returned by the debug delegate to specify how it processed -// the exception. -enum class ExceptionResult { - BreakInDebugger, // Break in the debugger and give the user a chance to - // interact with - // the program before continuing. - MaskException, // Eat the exception and don't let the application know it - // occurred. - SendToApplication // Send the exception to the application to be handled as if - // there were - // no debugger attached. -}; - -namespace lldb_private { - -class ProcessWindows; - -class IDebugDelegate; -class DebuggerThread; -class ExceptionRecord; - -typedef std::shared_ptr<IDebugDelegate> DebugDelegateSP; -typedef std::shared_ptr<DebuggerThread> DebuggerThreadSP; -typedef std::shared_ptr<ExceptionRecord> ExceptionRecordSP; -typedef std::unique_ptr<ExceptionRecord> ExceptionRecordUP; -} - -#endif diff --git a/source/Plugins/Process/Windows/Common/IDebugDelegate.h b/source/Plugins/Process/Windows/Common/IDebugDelegate.h deleted file mode 100644 index 73c285f1ecc79..0000000000000 --- a/source/Plugins/Process/Windows/Common/IDebugDelegate.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- IDebugDelegate.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_IDebugDelegate_H_ -#define liblldb_Plugins_Process_Windows_IDebugDelegate_H_ - -#include "ForwardDecl.h" -#include "lldb/lldb-forward.h" -#include "lldb/lldb-types.h" -#include <string> - -namespace lldb_private { -class Status; -class HostThread; - -//---------------------------------------------------------------------- -// IDebugDelegate -// -// IDebugDelegate defines an interface which allows implementors to receive -// notification of events that happen in a debugged process. -//---------------------------------------------------------------------- -class IDebugDelegate { -public: - virtual ~IDebugDelegate() {} - - virtual void OnExitProcess(uint32_t exit_code) = 0; - virtual void OnDebuggerConnected(lldb::addr_t image_base) = 0; - virtual ExceptionResult OnDebugException(bool first_chance, - const ExceptionRecord &record) = 0; - virtual void OnCreateThread(const HostThread &thread) = 0; - virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0; - virtual void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) = 0; - virtual void OnUnloadDll(lldb::addr_t module_addr) = 0; - virtual void OnDebugString(const std::string &string) = 0; - virtual void OnDebuggerError(const Status &error, uint32_t type) = 0; -}; -} - -#endif diff --git a/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp b/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp deleted file mode 100644 index 92aa7e2678b95..0000000000000 --- a/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===-- LocalDebugDelegate.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LocalDebugDelegate.h" -#include "ProcessWindows.h" - -using namespace lldb; -using namespace lldb_private; - -LocalDebugDelegate::LocalDebugDelegate(ProcessWP process) - : m_process(process) {} - -void LocalDebugDelegate::OnExitProcess(uint32_t exit_code) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnExitProcess(exit_code); -} - -void LocalDebugDelegate::OnDebuggerConnected(lldb::addr_t image_base) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebuggerConnected(image_base); -} - -ExceptionResult -LocalDebugDelegate::OnDebugException(bool first_chance, - const ExceptionRecord &record) { - if (ProcessWindowsSP process = GetProcessPointer()) - return process->OnDebugException(first_chance, record); - else - return ExceptionResult::MaskException; -} - -void LocalDebugDelegate::OnCreateThread(const HostThread &thread) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnCreateThread(thread); -} - -void LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, - uint32_t exit_code) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnExitThread(thread_id, exit_code); -} - -void LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnLoadDll(module_spec, module_addr); -} - -void LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnUnloadDll(module_addr); -} - -void LocalDebugDelegate::OnDebugString(const std::string &string) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebugString(string); -} - -void LocalDebugDelegate::OnDebuggerError(const Status &error, uint32_t type) { - if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebuggerError(error, type); -} - -ProcessWindowsSP LocalDebugDelegate::GetProcessPointer() { - ProcessSP process = m_process.lock(); - return std::static_pointer_cast<ProcessWindows>(process); -} diff --git a/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h b/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h deleted file mode 100644 index 2cb479ccce8ab..0000000000000 --- a/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h +++ /dev/null @@ -1,67 +0,0 @@ -//===-- LocalDebugDelegate.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_LocalDebugDelegate_H_ -#define liblldb_Plugins_Process_Windows_LocalDebugDelegate_H_ - -#include <memory> - -#include "IDebugDelegate.h" - -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class ProcessWindows; -typedef std::shared_ptr<ProcessWindows> ProcessWindowsSP; - -//---------------------------------------------------------------------- -// LocalDebugDelegate -// -// LocalDebugDelegate creates a connection between a ProcessWindows and the -// debug driver. This serves to decouple ProcessWindows from the debug -// driver. It would be possible to get a similar decoupling by just having -// ProcessWindows implement this interface directly. There are two reasons -// why we don't do this: -// -// 1) In the future when we add support for local debugging through LLGS, and we -// go through the Native*Protocol interface, it is likely we will need the -// additional flexibility provided by this sort of adapter pattern. -// 2) LLDB holds a shared_ptr to the ProcessWindows, and our driver thread -// needs access to it as well. To avoid a race condition, we want to make -// sure that we're also holding onto a shared_ptr. -// lldb_private::Process supports enable_shared_from_this, but that gives us -// a ProcessSP (which is exactly what we are trying to decouple from the -// driver), so this adapter serves as a way to transparently hold the -// ProcessSP while still keeping it decoupled from the driver. -//---------------------------------------------------------------------- -class LocalDebugDelegate : public IDebugDelegate { -public: - explicit LocalDebugDelegate(lldb::ProcessWP process); - - void OnExitProcess(uint32_t exit_code) override; - void OnDebuggerConnected(lldb::addr_t image_base) override; - ExceptionResult OnDebugException(bool first_chance, - const ExceptionRecord &record) override; - void OnCreateThread(const HostThread &thread) override; - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &message) override; - void OnDebuggerError(const Status &error, uint32_t type) override; - -private: - ProcessWindowsSP GetProcessPointer(); - - lldb::ProcessWP m_process; -}; -} - -#endif diff --git a/source/Plugins/Process/Windows/Common/NtStructures.h b/source/Plugins/Process/Windows/Common/NtStructures.h deleted file mode 100644 index 6826b98c769e7..0000000000000 --- a/source/Plugins/Process/Windows/Common/NtStructures.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- NtStructures.h ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_Common_NtStructures_h_ -#define liblldb_Plugins_Process_Windows_Common_NtStructures_h_ - -#include "lldb/Host/windows/windows.h" - -// This describes the layout of a TEB (Thread Environment Block) for a 64-bit -// process. It's adapted from the 32-bit TEB in winternl.h. Currently, we care -// only about the position of the TlsSlots. -struct TEB64 { - ULONG64 Reserved1[12]; - ULONG64 ProcessEnvironmentBlock; - ULONG64 Reserved2[399]; - BYTE Reserved3[1952]; - ULONG64 TlsSlots[64]; - BYTE Reserved4[8]; - ULONG64 Reserved5[26]; - ULONG64 ReservedForOle; // Windows 2000 only - ULONG64 Reserved6[4]; - ULONG64 TlsExpansionSlots; -}; - -#endif diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/source/Plugins/Process/Windows/Common/ProcessWindows.cpp deleted file mode 100644 index 3fe5ab7804cba..0000000000000 --- a/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ /dev/null @@ -1,1119 +0,0 @@ -//===-- ProcessWindows.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ProcessWindows.h" - -// Windows includes -#include "lldb/Host/windows/windows.h" -#include <psapi.h> - -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Section.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/HostNativeProcessBase.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/State.h" - -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" - -#include "DebuggerThread.h" -#include "ExceptionRecord.h" -#include "ForwardDecl.h" -#include "LocalDebugDelegate.h" -#include "ProcessWindowsLog.h" -#include "TargetThreadWindows.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { -std::string GetProcessExecutableName(HANDLE process_handle) { - std::vector<wchar_t> file_name; - DWORD file_name_size = MAX_PATH; // first guess, not an absolute limit - DWORD copied = 0; - do { - file_name_size *= 2; - file_name.resize(file_name_size); - copied = ::GetModuleFileNameExW(process_handle, NULL, file_name.data(), - file_name_size); - } while (copied >= file_name_size); - file_name.resize(copied); - std::string result; - llvm::convertWideToUTF8(file_name.data(), result); - return result; -} - -std::string GetProcessExecutableName(DWORD pid) { - std::string file_name; - HANDLE process_handle = - ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); - if (process_handle != NULL) { - file_name = GetProcessExecutableName(process_handle); - ::CloseHandle(process_handle); - } - return file_name; -} - -DWORD ConvertLldbToWinApiProtect(uint32_t protect) { - // We also can process a read / write permissions here, but if the debugger - // will make later a write into the allocated memory, it will fail. To get - // around it is possible inside DoWriteMemory to remember memory permissions, - // allow write, write and restore permissions, but for now we process only - // the executable permission. - // - // TODO: Process permissions other than executable - if (protect & ePermissionsExecutable) - return PAGE_EXECUTE_READWRITE; - - return PAGE_READWRITE; -} - -} // anonymous namespace - -namespace lldb_private { - -// We store a pointer to this class in the ProcessWindows, so that we don't -// expose Windows-specific types and implementation details from a public -// header file. -class ProcessWindowsData { -public: - ProcessWindowsData(bool stop_at_entry) : m_stop_at_entry(stop_at_entry) { - m_initial_stop_event = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - } - - ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } - - Status m_launch_error; - DebuggerThreadSP m_debugger; - StopInfoSP m_pending_stop_info; - HANDLE m_initial_stop_event = nullptr; - bool m_initial_stop_received = false; - bool m_stop_at_entry; - std::map<lldb::tid_t, HostThread> m_new_threads; - std::set<lldb::tid_t> m_exited_threads; -}; - -ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *) { - return ProcessSP(new ProcessWindows(target_sp, listener_sp)); -} - -void ProcessWindows::Initialize() { - static llvm::once_flag g_once_flag; - - llvm::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance); - }); -} - -void ProcessWindows::Terminate() {} - -lldb_private::ConstString ProcessWindows::GetPluginNameStatic() { - static ConstString g_name("windows"); - return g_name; -} - -const char *ProcessWindows::GetPluginDescriptionStatic() { - return "Process plugin for Windows"; -} - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessWindows::ProcessWindows(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp) - : lldb_private::Process(target_sp, listener_sp) {} - -ProcessWindows::~ProcessWindows() {} - -size_t ProcessWindows::GetSTDOUT(char *buf, size_t buf_size, Status &error) { - error.SetErrorString("GetSTDOUT unsupported on Windows"); - return 0; -} - -size_t ProcessWindows::GetSTDERR(char *buf, size_t buf_size, Status &error) { - error.SetErrorString("GetSTDERR unsupported on Windows"); - return 0; -} - -size_t ProcessWindows::PutSTDIN(const char *buf, size_t buf_size, - Status &error) { - error.SetErrorString("PutSTDIN unsupported on Windows"); - return 0; -} - -//------------------------------------------------------------------------------ -// ProcessInterface protocol. - -lldb_private::ConstString ProcessWindows::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t ProcessWindows::GetPluginVersion() { return 1; } - -Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS); - LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site, - bp_site->GetID(), bp_site->GetLoadAddress()); - - Status error = EnableSoftwareBreakpoint(bp_site); - if (!error.Success()) - LLDB_LOG(log, "error: {0}", error); - return error; -} - -Status ProcessWindows::DisableBreakpointSite(BreakpointSite *bp_site) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS); - LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site, - bp_site->GetID(), bp_site->GetLoadAddress()); - - Status error = DisableSoftwareBreakpoint(bp_site); - - if (!error.Success()) - LLDB_LOG(log, "error: {0}", error); - return error; -} - -Status ProcessWindows::DoDetach(bool keep_stopped) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire the lock only long enough to get the DebuggerThread. - // StopDebugging() will trigger a call back into ProcessWindows which will - // also acquire the lock. Thus we have to release the lock before calling - // StopDebugging(). - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) { - LLDB_LOG(log, "state = {0}, but there is no active session.", - private_state); - return Status(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Status error; - if (private_state != eStateExited && private_state != eStateDetached) { - LLDB_LOG(log, "detaching from process {0} while state = {1}.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - error = debugger_thread->StopDebugging(false); - if (error.Success()) { - SetPrivateState(eStateDetached); - } - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } else { - LLDB_LOG( - log, - "error: process {0} in state = {1}, but cannot destroy in this state.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - } - - return error; -} - -Status ProcessWindows::DoLaunch(Module *exe_module, - ProcessLaunchInfo &launch_info) { - // Even though m_session_data is accessed here, it is before a debugger - // thread has been kicked off. So there's no race conditions, and it - // shouldn't be necessary to acquire the mutex. - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - Status result; - - FileSpec working_dir = launch_info.GetWorkingDirectory(); - namespace fs = llvm::sys::fs; - if (working_dir) { - FileSystem::Instance().Resolve(working_dir); - if (!FileSystem::Instance().IsDirectory(working_dir)) { - result.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - return result; - } - } - - if (!launch_info.GetFlags().Test(eLaunchFlagDebug)) { - StreamString stream; - stream.Printf("ProcessWindows unable to launch '%s'. ProcessWindows can " - "only be used for debug launches.", - launch_info.GetExecutableFile().GetPath().c_str()); - std::string message = stream.GetString(); - result.SetErrorString(message.c_str()); - - LLDB_LOG(log, "error: {0}", message); - return result; - } - - bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry); - m_session_data.reset(new ProcessWindowsData(stop_at_entry)); - - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - m_session_data->m_debugger.reset(new DebuggerThread(delegate)); - DebuggerThreadSP debugger = m_session_data->m_debugger; - - // Kick off the DebugLaunch asynchronously and wait for it to complete. - result = debugger->DebugLaunch(launch_info); - if (result.Fail()) { - LLDB_LOG(log, "failed launching '{0}'. {1}", - launch_info.GetExecutableFile().GetPath(), result); - return result; - } - - HostProcess process; - Status error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - LLDB_LOG(log, "failed launching '{0}'. {1}", - launch_info.GetExecutableFile().GetPath(), error); - return error; - } - - LLDB_LOG(log, "successfully launched '{0}'", - launch_info.GetExecutableFile().GetPath()); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state should already be set to eStateStopped as a result of - // hitting the initial breakpoint. If it was not set, the breakpoint should - // have already been resumed from and the private state should already be - // eStateRunning. - launch_info.SetProcessID(process.GetProcessId()); - SetID(process.GetProcessId()); - - return result; -} - -Status -ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid, - const ProcessAttachInfo &attach_info) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - m_session_data.reset( - new ProcessWindowsData(!attach_info.GetContinueOnceAttached())); - - DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this())); - DebuggerThreadSP debugger(new DebuggerThread(delegate)); - - m_session_data->m_debugger = debugger; - - DWORD process_id = static_cast<DWORD>(pid); - Status error = debugger->DebugAttach(process_id, attach_info); - if (error.Fail()) { - LLDB_LOG( - log, - "encountered an error occurred initiating the asynchronous attach. {0}", - error); - return error; - } - - HostProcess process; - error = WaitForDebuggerConnection(debugger, process); - if (error.Fail()) { - LLDB_LOG(log, - "encountered an error waiting for the debugger to connect. {0}", - error); - return error; - } - - LLDB_LOG(log, "successfully attached to process with pid={0}", process_id); - - // We've hit the initial stop. If eLaunchFlagsStopAtEntry was specified, the - // private state should already be set to eStateStopped as a result of - // hitting the initial breakpoint. If it was not set, the breakpoint should - // have already been resumed from and the private state should already be - // eStateRunning. - SetID(process.GetProcessId()); - return error; -} - -Status ProcessWindows::DoResume() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - llvm::sys::ScopedLock lock(m_mutex); - Status error; - - StateType private_state = GetPrivateState(); - if (private_state == eStateStopped || private_state == eStateCrashed) { - LLDB_LOG(log, "process {0} is in state {1}. Resuming...", - m_session_data->m_debugger->GetProcess().GetProcessId(), - GetPrivateState()); - - ExceptionRecordSP active_exception = - m_session_data->m_debugger->GetActiveException().lock(); - if (active_exception) { - // Resume the process and continue processing debug events. Mask the - // exception so that from the process's view, there is no indication that - // anything happened. - m_session_data->m_debugger->ContinueAsyncException( - ExceptionResult::MaskException); - } - - LLDB_LOG(log, "resuming {0} threads.", m_thread_list.GetSize()); - - bool failed = false; - for (uint32_t i = 0; i < m_thread_list.GetSize(); ++i) { - auto thread = std::static_pointer_cast<TargetThreadWindows>( - m_thread_list.GetThreadAtIndex(i)); - Status result = thread->DoResume(); - if (result.Fail()) { - failed = true; - LLDB_LOG( - log, - "Trying to resume thread at index {0}, but failed with error {1}.", - i, result); - } - } - - if (failed) { - error.SetErrorString("ProcessWindows::DoResume failed"); - return error; - } else { - SetPrivateState(eStateRunning); - } - } else { - LLDB_LOG(log, "error: process {0} is in state {1}. Returning...", - m_session_data->m_debugger->GetProcess().GetProcessId(), - GetPrivateState()); - } - return error; -} - -Status ProcessWindows::DoDestroy() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - DebuggerThreadSP debugger_thread; - StateType private_state; - { - // Acquire this lock inside an inner scope, only long enough to get the - // DebuggerThread. StopDebugging() will trigger a call back into - // ProcessWindows which will acquire the lock again, so we need to not - // deadlock. - llvm::sys::ScopedLock lock(m_mutex); - - private_state = GetPrivateState(); - - if (!m_session_data) { - LLDB_LOG(log, "warning: state = {0}, but there is no active session.", - private_state); - return Status(); - } - - debugger_thread = m_session_data->m_debugger; - } - - Status error; - if (private_state != eStateExited && private_state != eStateDetached) { - LLDB_LOG(log, "Shutting down process {0} while state = {1}.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - error = debugger_thread->StopDebugging(true); - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } else { - LLDB_LOG(log, "cannot destroy process {0} while state = {1}", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle(), - private_state); - } - - return error; -} - -Status ProcessWindows::DoHalt(bool &caused_stop) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - Status error; - StateType state = GetPrivateState(); - if (state == eStateStopped) - caused_stop = false; - else { - llvm::sys::ScopedLock lock(m_mutex); - caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess() - .GetNativeProcess() - .GetSystemHandle()); - if (!caused_stop) { - error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "DebugBreakProcess failed with error {0}", error); - } - } - return error; -} - -void ProcessWindows::DidLaunch() { - ArchSpec arch_spec; - DidAttach(arch_spec); -} - -void ProcessWindows::DidAttach(ArchSpec &arch_spec) { - llvm::sys::ScopedLock lock(m_mutex); - - // The initial stop won't broadcast the state change event, so account for - // that here. - if (m_session_data && GetPrivateState() == eStateStopped && - m_session_data->m_stop_at_entry) - RefreshStateAfterStop(); -} - -void ProcessWindows::RefreshStateAfterStop() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION); - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) { - LLDB_LOG(log, "no active session. Returning..."); - return; - } - - m_thread_list.RefreshStateAfterStop(); - - std::weak_ptr<ExceptionRecord> exception_record = - m_session_data->m_debugger->GetActiveException(); - ExceptionRecordSP active_exception = exception_record.lock(); - if (!active_exception) { - LLDB_LOG(log, - "there is no active exception in process {0}. Why is the " - "process stopped?", - m_session_data->m_debugger->GetProcess().GetProcessId()); - return; - } - - StopInfoSP stop_info; - m_thread_list.SetSelectedThreadByID(active_exception->GetThreadID()); - ThreadSP stop_thread = m_thread_list.GetSelectedThread(); - if (!stop_thread) - return; - - switch (active_exception->GetExceptionCode()) { - case EXCEPTION_SINGLE_STEP: { - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - const uint64_t pc = register_context->GetPC(); - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - if (site && site->ValidForThisThread(stop_thread.get())) { - LLDB_LOG(log, - "Single-stepped onto a breakpoint in process {0} at " - "address {1:x} with breakpoint site {2}", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, - site->GetID()); - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, - site->GetID()); - stop_thread->SetStopInfo(stop_info); - } else { - LLDB_LOG(log, "single stepping thread {0}", stop_thread->GetID()); - stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread); - stop_thread->SetStopInfo(stop_info); - } - return; - } - - case EXCEPTION_BREAKPOINT: { - RegisterContextSP register_context = stop_thread->GetRegisterContext(); - - // The current EIP is AFTER the BP opcode, which is one byte. - uint64_t pc = register_context->GetPC() - 1; - - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - if (site) { - LLDB_LOG(log, - "detected breakpoint in process {0} at address {1:x} with " - "breakpoint site {2}", - m_session_data->m_debugger->GetProcess().GetProcessId(), pc, - site->GetID()); - - if (site->ValidForThisThread(stop_thread.get())) { - LLDB_LOG(log, - "Breakpoint site {0} is valid for this thread ({1:x}), " - "creating stop info.", - site->GetID(), stop_thread->GetID()); - - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *stop_thread, site->GetID()); - register_context->SetPC(pc); - } else { - LLDB_LOG(log, - "Breakpoint site {0} is not valid for this thread, " - "creating empty stop info.", - site->GetID()); - } - stop_thread->SetStopInfo(stop_info); - return; - } else { - // The thread hit a hard-coded breakpoint like an `int 3` or - // `__debugbreak()`. - LLDB_LOG(log, - "No breakpoint site matches for this thread. __debugbreak()? " - "Creating stop info with the exception."); - // FALLTHROUGH: We'll treat this as a generic exception record in the - // default case. - } - } - - default: { - std::string desc; - llvm::raw_string_ostream desc_stream(desc); - desc_stream << "Exception " - << llvm::format_hex(active_exception->GetExceptionCode(), 8) - << " encountered at address " - << llvm::format_hex(active_exception->GetExceptionAddress(), 8); - stop_info = StopInfo::CreateStopReasonWithException( - *stop_thread, desc_stream.str().c_str()); - stop_thread->SetStopInfo(stop_info); - LLDB_LOG(log, "{0}", desc_stream.str()); - return; - } - } -} - -bool ProcessWindows::CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) { - if (plugin_specified_by_name) - return true; - - // 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 FileSystem::Instance().Exists(exe_module_sp->GetFileSpec()); - // However, if there is no executable module, we return true since we might - // be preparing to attach. - return true; -} - -bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD); - // Add all the threads that were previously running and for which we did not - // detect a thread exited event. - int new_size = 0; - int continued_threads = 0; - int exited_threads = 0; - int new_threads = 0; - - for (ThreadSP old_thread : old_thread_list.Threads()) { - lldb::tid_t old_thread_id = old_thread->GetID(); - auto exited_thread_iter = - m_session_data->m_exited_threads.find(old_thread_id); - if (exited_thread_iter == m_session_data->m_exited_threads.end()) { - new_thread_list.AddThread(old_thread); - ++new_size; - ++continued_threads; - LLDB_LOGV(log, "Thread {0} was running and is still running.", - old_thread_id); - } else { - LLDB_LOGV(log, "Thread {0} was running and has exited.", old_thread_id); - ++exited_threads; - } - } - - // Also add all the threads that are new since the last time we broke into - // the debugger. - for (const auto &thread_info : m_session_data->m_new_threads) { - ThreadSP thread(new TargetThreadWindows(*this, thread_info.second)); - thread->SetID(thread_info.first); - new_thread_list.AddThread(thread); - ++new_size; - ++new_threads; - LLDB_LOGV(log, "Thread {0} is new since last update.", thread_info.first); - } - - LLDB_LOG(log, "{0} new threads, {1} old threads, {2} exited threads.", - new_threads, continued_threads, exited_threads); - - m_session_data->m_new_threads.clear(); - m_session_data->m_exited_threads.clear(); - - return new_size > 0; -} - -bool ProcessWindows::IsAlive() { - StateType state = GetPrivateState(); - switch (state) { - case eStateCrashed: - case eStateDetached: - case eStateUnloaded: - case eStateExited: - case eStateInvalid: - return false; - default: - return true; - } -} - -size_t ProcessWindows::DoReadMemory(lldb::addr_t vm_addr, void *buf, - size_t size, Status &error) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - - if (!m_session_data) - return 0; - - LLDB_LOG(log, "attempting to read {0} bytes from address {1:x}", size, - vm_addr); - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T bytes_read = 0; - if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, - buf, size, &bytes_read)) { - // Reading from the process can fail for a number of reasons - set the - // error code and make sure that the number of bytes read is set back to 0 - // because in some scenarios the value of bytes_read returned from the API - // is garbage. - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "reading failed with error: {0}", error); - bytes_read = 0; - } - return bytes_read; -} - -size_t ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, - size_t size, Status &error) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to write {0} bytes into address {1:x}", size, - vm_addr); - - if (!m_session_data) { - LLDB_LOG(log, "cannot write, there is no active debugger connection."); - return 0; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - void *addr = reinterpret_cast<void *>(vm_addr); - SIZE_T bytes_written = 0; - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (WriteProcessMemory(handle, addr, buf, size, &bytes_written)) - FlushInstructionCache(handle, addr, bytes_written); - else { - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "writing failed with error: {0}", error); - } - return bytes_written; -} - -lldb::addr_t ProcessWindows::DoAllocateMemory(size_t size, uint32_t permissions, - Status &error) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to allocate {0} bytes with permissions {1}", size, - permissions); - - if (!m_session_data) { - LLDB_LOG(log, "cannot allocate, there is no active debugger connection."); - error.SetErrorString( - "cannot allocate, there is no active debugger connection"); - return LLDB_INVALID_ADDRESS; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - auto protect = ConvertLldbToWinApiProtect(permissions); - auto result = VirtualAllocEx(handle, nullptr, size, MEM_COMMIT, protect); - if (!result) { - error.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "allocating failed with error: {0}", error); - return LLDB_INVALID_ADDRESS; - } - - return reinterpret_cast<addr_t>(result); -} - -Status ProcessWindows::DoDeallocateMemory(lldb::addr_t ptr) { - Status result; - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - llvm::sys::ScopedLock lock(m_mutex); - LLDB_LOG(log, "attempting to deallocate bytes at address {0}", ptr); - - if (!m_session_data) { - LLDB_LOG(log, "cannot deallocate, there is no active debugger connection."); - result.SetErrorString( - "cannot deallocate, there is no active debugger connection"); - return result; - } - - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (!VirtualFreeEx(handle, reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE)) { - result.SetError(GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, "deallocating failed with error: {0}", result); - return result; - } - - return result; -} - -Status ProcessWindows::GetMemoryRegionInfo(lldb::addr_t vm_addr, - MemoryRegionInfo &info) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_MEMORY); - Status error; - llvm::sys::ScopedLock lock(m_mutex); - info.Clear(); - - if (!m_session_data) { - error.SetErrorString( - "GetMemoryRegionInfo called with no debugging session."); - LLDB_LOG(log, "error: {0}", error); - return error; - } - HostProcess process = m_session_data->m_debugger->GetProcess(); - lldb::process_t handle = process.GetNativeProcess().GetSystemHandle(); - if (handle == nullptr || handle == LLDB_INVALID_PROCESS) { - error.SetErrorString( - "GetMemoryRegionInfo called with an invalid target process."); - LLDB_LOG(log, "error: {0}", error); - return error; - } - - LLDB_LOG(log, "getting info for address {0:x}", vm_addr); - - void *addr = reinterpret_cast<void *>(vm_addr); - MEMORY_BASIC_INFORMATION mem_info = {}; - SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); - if (result == 0) { - if (::GetLastError() == ERROR_INVALID_PARAMETER) { - // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with - // an address past the highest accessible address. We should return a - // range from the vm_addr to LLDB_INVALID_ADDRESS - info.GetRange().SetRangeBase(vm_addr); - info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); - info.SetReadable(MemoryRegionInfo::eNo); - info.SetExecutable(MemoryRegionInfo::eNo); - info.SetWritable(MemoryRegionInfo::eNo); - info.SetMapped(MemoryRegionInfo::eNo); - return error; - } else { - error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOG(log, - "VirtualQueryEx returned error {0} while getting memory " - "region info for address {1:x}", - error, vm_addr); - return error; - } - } - - // Protect bits are only valid for MEM_COMMIT regions. - if (mem_info.State == MEM_COMMIT) { - const bool readable = IsPageReadable(mem_info.Protect); - const bool executable = IsPageExecutable(mem_info.Protect); - const bool writable = IsPageWritable(mem_info.Protect); - info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - info.SetExecutable(executable ? MemoryRegionInfo::eYes - : MemoryRegionInfo::eNo); - info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); - } else { - info.SetReadable(MemoryRegionInfo::eNo); - info.SetExecutable(MemoryRegionInfo::eNo); - info.SetWritable(MemoryRegionInfo::eNo); - } - - // AllocationBase is defined for MEM_COMMIT and MEM_RESERVE but not MEM_FREE. - if (mem_info.State != MEM_FREE) { - info.GetRange().SetRangeBase( - reinterpret_cast<addr_t>(mem_info.AllocationBase)); - info.GetRange().SetRangeEnd(reinterpret_cast<addr_t>(mem_info.BaseAddress) + - mem_info.RegionSize); - info.SetMapped(MemoryRegionInfo::eYes); - } else { - // In the unmapped case we need to return the distance to the next block of - // memory. VirtualQueryEx nearly does that except that it gives the - // distance from the start of the page containing vm_addr. - SYSTEM_INFO data; - GetSystemInfo(&data); - DWORD page_offset = vm_addr % data.dwPageSize; - info.GetRange().SetRangeBase(vm_addr); - info.GetRange().SetByteSize(mem_info.RegionSize - page_offset); - info.SetMapped(MemoryRegionInfo::eNo); - } - - error.SetError(::GetLastError(), eErrorTypeWin32); - LLDB_LOGV(log, - "Memory region info for address {0}: readable={1}, " - "executable={2}, writable={3}", - vm_addr, info.GetReadable(), info.GetExecutable(), - info.GetWritable()); - return error; -} - -lldb::addr_t ProcessWindows::GetImageInfoAddress() { - Target &target = GetTarget(); - ObjectFile *obj_file = target.GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(&target); - if (addr.IsValid()) - return addr.GetLoadAddress(&target); - else - return LLDB_INVALID_ADDRESS; -} - -void ProcessWindows::OnExitProcess(uint32_t exit_code) { - // No need to acquire the lock since m_session_data isn't accessed. - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code); - - TargetSP target = CalculateTarget(); - if (target) { - ModuleSP executable_module = target->GetExecutableModule(); - ModuleList unloaded_modules; - unloaded_modules.Append(executable_module); - target->ModulesDidUnload(unloaded_modules, true); - } - - SetProcessExitStatus(GetID(), true, 0, exit_code); - SetPrivateState(eStateExited); - - // If the process exits before any initial stop then notify the debugger - // of the error otherwise WaitForDebuggerConnection() will be blocked. - // An example of this issue is when a process fails to load a dependent DLL. - if (m_session_data && !m_session_data->m_initial_stop_received) { - Status error(exit_code, eErrorTypeWin32); - OnDebuggerError(error, 0); - } -} - -void ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { - DebuggerThreadSP debugger = m_session_data->m_debugger; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}", - debugger->GetProcess().GetProcessId(), image_base); - - ModuleSP module = GetTarget().GetExecutableModule(); - if (!module) { - // During attach, we won't have the executable module, so find it now. - const DWORD pid = debugger->GetProcess().GetProcessId(); - const std::string file_name = GetProcessExecutableName(pid); - if (file_name.empty()) { - return; - } - - FileSpec executable_file(file_name); - FileSystem::Instance().Resolve(executable_file); - ModuleSpec module_spec(executable_file); - Status error; - module = GetTarget().GetSharedModule(module_spec, &error); - if (!module) { - return; - } - - GetTarget().SetExecutableModule(module, eLoadDependentsNo); - } - - bool load_addr_changed; - module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); - - // Add the main executable module to the list of pending module loads. We - // can't call GetTarget().ModulesDidLoad() here because we still haven't - // returned from DoLaunch() / DoAttach() yet so the target may not have set - // the process instance to `this` yet. - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wmain_thread = - debugger->GetMainThread().GetNativeThread(); - m_session_data->m_new_threads[wmain_thread.GetThreadId()] = - debugger->GetMainThread(); -} - -ExceptionResult -ProcessWindows::OnDebugException(bool first_chance, - const ExceptionRecord &record) { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_EXCEPTION); - llvm::sys::ScopedLock lock(m_mutex); - - // FIXME: Without this check, occasionally when running the test suite there - // is - // an issue where m_session_data can be null. It's not clear how this could - // happen but it only surfaces while running the test suite. In order to - // properly diagnose this, we probably need to first figure allow the test - // suite to print out full lldb logs, and then add logging to the process - // plugin. - if (!m_session_data) { - LLDB_LOG(log, - "Debugger thread reported exception {0:x} at address {1:x}, " - "but there is no session.", - record.GetExceptionCode(), record.GetExceptionAddress()); - return ExceptionResult::SendToApplication; - } - - if (!first_chance) { - // Not any second chance exception is an application crash by definition. - // It may be an expression evaluation crash. - SetPrivateState(eStateStopped); - } - - ExceptionResult result = ExceptionResult::SendToApplication; - switch (record.GetExceptionCode()) { - case EXCEPTION_BREAKPOINT: - // Handle breakpoints at the first chance. - result = ExceptionResult::BreakInDebugger; - - if (!m_session_data->m_initial_stop_received) { - LLDB_LOG( - log, - "Hit loader breakpoint at address {0:x}, setting initial stop event.", - record.GetExceptionAddress()); - m_session_data->m_initial_stop_received = true; - ::SetEvent(m_session_data->m_initial_stop_event); - } else { - LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", - record.GetExceptionAddress()); - } - SetPrivateState(eStateStopped); - break; - case EXCEPTION_SINGLE_STEP: - result = ExceptionResult::BreakInDebugger; - SetPrivateState(eStateStopped); - break; - default: - LLDB_LOG(log, - "Debugger thread reported exception {0:x} at address {1:x} " - "(first_chance={2})", - record.GetExceptionCode(), record.GetExceptionAddress(), - first_chance); - // For non-breakpoints, give the application a chance to handle the - // exception first. - if (first_chance) - result = ExceptionResult::SendToApplication; - else - result = ExceptionResult::BreakInDebugger; - } - - return result; -} - -void ProcessWindows::OnCreateThread(const HostThread &new_thread) { - llvm::sys::ScopedLock lock(m_mutex); - const HostThreadWindows &wnew_thread = new_thread.GetNativeThread(); - m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread; -} - -void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { - llvm::sys::ScopedLock lock(m_mutex); - - // On a forced termination, we may get exit thread events after the session - // data has been cleaned up. - if (!m_session_data) - return; - - // A thread may have started and exited before the debugger stopped allowing a - // refresh. - // Just remove it from the new threads list in that case. - auto iter = m_session_data->m_new_threads.find(thread_id); - if (iter != m_session_data->m_new_threads.end()) - m_session_data->m_new_threads.erase(iter); - else - m_session_data->m_exited_threads.insert(thread_id); -} - -void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { - // Confusingly, there is no Target::AddSharedModule. Instead, calling - // GetSharedModule() with a new module will add it to the module list and - // return a corresponding ModuleSP. - Status error; - ModuleSP module = GetTarget().GetSharedModule(module_spec, &error); - bool load_addr_changed = false; - module->SetLoadAddress(GetTarget(), module_addr, false, load_addr_changed); - - ModuleList loaded_modules; - loaded_modules.Append(module); - GetTarget().ModulesDidLoad(loaded_modules); -} - -void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { - Address resolved_addr; - if (GetTarget().ResolveLoadAddress(module_addr, resolved_addr)) { - ModuleSP module = resolved_addr.GetModule(); - if (module) { - ModuleList unloaded_modules; - unloaded_modules.Append(module); - GetTarget().ModulesDidUnload(unloaded_modules, false); - } - } -} - -void ProcessWindows::OnDebugString(const std::string &string) {} - -void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) { - llvm::sys::ScopedLock lock(m_mutex); - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS); - - if (m_session_data->m_initial_stop_received) { - // This happened while debugging. Do we shutdown the debugging session, - // try to continue, or do something else? - LLDB_LOG(log, - "Error {0} occurred during debugging. Unexpected behavior " - "may result. {1}", - error.GetError(), error); - } else { - // If we haven't actually launched the process yet, this was an error - // launching the process. Set the internal error and signal the initial - // stop event so that the DoLaunch method wakes up and returns a failure. - m_session_data->m_launch_error = error; - ::SetEvent(m_session_data->m_initial_stop_event); - LLDB_LOG( - log, - "Error {0} occurred launching the process before the initial stop. {1}", - error.GetError(), error); - return; - } -} - -Status ProcessWindows::WaitForDebuggerConnection(DebuggerThreadSP debugger, - HostProcess &process) { - Status result; - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_PROCESS | - WINDOWS_LOG_BREAKPOINTS); - LLDB_LOG(log, "Waiting for loader breakpoint."); - - // Block this function until we receive the initial stop from the process. - if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == - WAIT_OBJECT_0) { - LLDB_LOG(log, "hit loader breakpoint, returning."); - - process = debugger->GetProcess(); - return m_session_data->m_launch_error; - } else - return Status(::GetLastError(), eErrorTypeWin32); -} - -// The Windows page protection bits are NOT independent masks that can be -// bitwise-ORed together. For example, PAGE_EXECUTE_READ is not (PAGE_EXECUTE -// | PAGE_READ). To test for an access type, it's necessary to test for any of -// the bits that provide that access type. -bool ProcessWindows::IsPageReadable(uint32_t protect) { - return (protect & PAGE_NOACCESS) == 0; -} - -bool ProcessWindows::IsPageWritable(uint32_t protect) { - return (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY | - PAGE_READWRITE | PAGE_WRITECOPY)) != 0; -} - -bool ProcessWindows::IsPageExecutable(uint32_t protect) { - return (protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | - PAGE_EXECUTE_WRITECOPY)) != 0; -} - -} // namespace lldb_private diff --git a/source/Plugins/Process/Windows/Common/ProcessWindows.h b/source/Plugins/Process/Windows/Common/ProcessWindows.h deleted file mode 100644 index 00e384f584080..0000000000000 --- a/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ /dev/null @@ -1,121 +0,0 @@ -//===-- ProcessWindows.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ -#define liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ - -#include "lldb/Target/Process.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-forward.h" - -#include "llvm/Support/Mutex.h" - -#include "IDebugDelegate.h" - -namespace lldb_private { - -class HostProcess; -class ProcessWindowsData; - -class ProcessWindows : public Process, public IDebugDelegate { -public: - //------------------------------------------------------------------ - // Static functions. - //------------------------------------------------------------------ - static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, - lldb::ListenerSP listener_sp, - const FileSpec *); - - static void Initialize(); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Constructors and destructors - //------------------------------------------------------------------ - ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); - - ~ProcessWindows(); - - size_t GetSTDOUT(char *buf, size_t buf_size, Status &error) override; - size_t GetSTDERR(char *buf, size_t buf_size, Status &error) override; - size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) override; - - // lldb_private::Process overrides - ConstString GetPluginName() override; - uint32_t GetPluginVersion() override; - - Status EnableBreakpointSite(BreakpointSite *bp_site) override; - Status DisableBreakpointSite(BreakpointSite *bp_site) override; - - Status DoDetach(bool keep_stopped) override; - Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; - Status DoAttachToProcessWithID( - lldb::pid_t pid, - const lldb_private::ProcessAttachInfo &attach_info) override; - Status DoResume() override; - Status DoDestroy() override; - Status DoHalt(bool &caused_stop) override; - - void DidLaunch() override; - void DidAttach(lldb_private::ArchSpec &arch_spec) override; - - void RefreshStateAfterStop() override; - - bool CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) override; - bool DestroyRequiresHalt() override { return false; } - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; - bool IsAlive() override; - - size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) override; - size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, - Status &error) override; - lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions, - Status &error) override; - Status DoDeallocateMemory(lldb::addr_t ptr) override; - Status GetMemoryRegionInfo(lldb::addr_t vm_addr, - MemoryRegionInfo &info) override; - - lldb::addr_t GetImageInfoAddress() override; - - // IDebugDelegate overrides. - void OnExitProcess(uint32_t exit_code) override; - void OnDebuggerConnected(lldb::addr_t image_base) override; - ExceptionResult OnDebugException(bool first_chance, - const ExceptionRecord &record) override; - void OnCreateThread(const HostThread &thread) override; - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &string) override; - void OnDebuggerError(const Status &error, uint32_t type) override; - -private: - Status WaitForDebuggerConnection(DebuggerThreadSP debugger, - HostProcess &process); - - // These decode the page protection bits. - static bool IsPageReadable(uint32_t protect); - static bool IsPageWritable(uint32_t protect); - static bool IsPageExecutable(uint32_t protect); - - llvm::sys::Mutex m_mutex; - std::unique_ptr<ProcessWindowsData> m_session_data; -}; -} - -#endif // liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_ diff --git a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp deleted file mode 100644 index 386e9a5816c5f..0000000000000 --- a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//===-- ProcessWindowsLog.cpp -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ProcessWindowsLog.h" - -using namespace lldb_private; - -static constexpr Log::Category g_categories[] = { - {{"break"}, {"log breakpoints"}, WINDOWS_LOG_BREAKPOINTS}, - {{"event"}, {"log low level debugger events"}, WINDOWS_LOG_EVENT}, - {{"exception"}, {"log exception information"}, WINDOWS_LOG_EXCEPTION}, - {{"memory"}, {"log memory reads and writes"}, WINDOWS_LOG_MEMORY}, - {{"process"}, {"log process events and activities"}, WINDOWS_LOG_PROCESS}, - {{"registers"}, {"log register read/writes"}, WINDOWS_LOG_REGISTERS}, - {{"step"}, {"log step related activities"}, WINDOWS_LOG_STEP}, - {{"thread"}, {"log thread events and activities"}, WINDOWS_LOG_THREAD}, -}; - -Log::Channel ProcessWindowsLog::g_channel(g_categories, WINDOWS_LOG_PROCESS); - -void ProcessWindowsLog::Initialize() { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { Log::Register("windows", g_channel); }); -} - -void ProcessWindowsLog::Terminate() {} - - - - - - - - - diff --git a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h b/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h deleted file mode 100644 index b7f59c7081431..0000000000000 --- a/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h +++ /dev/null @@ -1,36 +0,0 @@ -//===-- ProcessWindowsLog.h -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessWindowsLog_h_ -#define liblldb_ProcessWindowsLog_h_ - -#include "lldb/Utility/Log.h" - -#define WINDOWS_LOG_PROCESS (1u << 1) // Log process operations -#define WINDOWS_LOG_EXCEPTION (1u << 1) // Log exceptions -#define WINDOWS_LOG_THREAD (1u << 2) // Log thread operations -#define WINDOWS_LOG_MEMORY (1u << 3) // Log memory reads/writes calls -#define WINDOWS_LOG_BREAKPOINTS (1u << 4) // Log breakpoint operations -#define WINDOWS_LOG_STEP (1u << 5) // Log step operations -#define WINDOWS_LOG_REGISTERS (1u << 6) // Log register operations -#define WINDOWS_LOG_EVENT (1u << 7) // Low level debug events - -namespace lldb_private { -class ProcessWindowsLog { - static Log::Channel g_channel; - -public: - static void Initialize(); - static void Terminate(); - - static Log *GetLogIfAny(uint32_t mask) { return g_channel.GetLogIfAny(mask); } -}; -} - -#endif // liblldb_ProcessWindowsLog_h_ diff --git a/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp b/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp deleted file mode 100644 index 90d43b2cf8284..0000000000000 --- a/source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp +++ /dev/null @@ -1,136 +0,0 @@ -//===-- RegisterContextWindows.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/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-private-types.h" - -#include "ProcessWindowsLog.h" -#include "RegisterContextWindows.h" -#include "TargetThreadWindows.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -const DWORD kWinContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows::RegisterContextWindows(Thread &thread, - uint32_t concrete_frame_idx) - : RegisterContext(thread, concrete_frame_idx), m_context(), - m_context_stale(true) {} - -RegisterContextWindows::~RegisterContextWindows() {} - -void RegisterContextWindows::InvalidateAllRegisters() { - m_context_stale = true; -} - -bool RegisterContextWindows::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - - if (!CacheAllRegisterValues()) - return false; - - data_sp.reset(new DataBufferHeap(sizeof(CONTEXT), 0)); - memcpy(data_sp->GetBytes(), &m_context, sizeof(m_context)); - - return true; -} - -bool RegisterContextWindows::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - assert(data_sp->GetByteSize() >= sizeof(m_context)); - memcpy(&m_context, data_sp->GetBytes(), sizeof(m_context)); - - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - if (!::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), - &m_context)) - return false; - - return true; -} - -uint32_t RegisterContextWindows::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) { - const uint32_t num_regs = GetRegisterCount(); - - assert(kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - - if (reg_info->kinds[kind] == num) - return reg_idx; - } - - return LLDB_INVALID_REGNUM; -} - -//------------------------------------------------------------------ -// Subclasses can these functions if desired -//------------------------------------------------------------------ -uint32_t RegisterContextWindows::NumSupportedHardwareBreakpoints() { - // Support for hardware breakpoints not yet implemented. - return 0; -} - -uint32_t RegisterContextWindows::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - return 0; -} - -bool RegisterContextWindows::ClearHardwareBreakpoint(uint32_t hw_idx) { - return false; -} - -uint32_t RegisterContextWindows::NumSupportedHardwareWatchpoints() { - // Support for hardware watchpoints not yet implemented. - return 0; -} - -uint32_t RegisterContextWindows::SetHardwareWatchpoint(lldb::addr_t addr, - size_t size, bool read, - bool write) { - return 0; -} - -bool RegisterContextWindows::ClearHardwareWatchpoint(uint32_t hw_index) { - return false; -} - -bool RegisterContextWindows::HardwareSingleStep(bool enable) { return false; } - -bool RegisterContextWindows::CacheAllRegisterValues() { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); - if (!m_context_stale) - return true; - - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - memset(&m_context, 0, sizeof(m_context)); - m_context.ContextFlags = kWinContextFlags; - if (!::GetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), - &m_context)) { - LLDB_LOG( - log, - "GetThreadContext failed with error {0} while caching register values.", - ::GetLastError()); - return false; - } - LLDB_LOG(log, "successfully updated the register values."); - m_context_stale = false; - return true; -} diff --git a/source/Plugins/Process/Windows/Common/RegisterContextWindows.h b/source/Plugins/Process/Windows/Common/RegisterContextWindows.h deleted file mode 100644 index bd09295c2f238..0000000000000 --- a/source/Plugins/Process/Windows/Common/RegisterContextWindows.h +++ /dev/null @@ -1,67 +0,0 @@ -//===-- RegisterContextWindows.h --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextWindows_H_ -#define liblldb_RegisterContextWindows_H_ - -#include "lldb/Target/RegisterContext.h" -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class Thread; - -class RegisterContextWindows : public lldb_private::RegisterContext { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - void InvalidateAllRegisters() override; - - bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; - - bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - - uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, - uint32_t num) override; - - //------------------------------------------------------------------ - // Subclasses can override these functions if desired - //------------------------------------------------------------------ - uint32_t NumSupportedHardwareBreakpoints() override; - - uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - bool ClearHardwareBreakpoint(uint32_t hw_idx) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, - bool write) override; - - bool ClearHardwareWatchpoint(uint32_t hw_index) override; - - bool HardwareSingleStep(bool enable) override; - -protected: - virtual bool CacheAllRegisterValues(); - - CONTEXT m_context; - bool m_context_stale; -}; -} - -#endif // #ifndef liblldb_RegisterContextWindows_H_ diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp deleted file mode 100644 index b121dc7bf15ea..0000000000000 --- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//===-- TargetThreadWindows.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/Host/HostInfo.h" -#include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Logging.h" -#include "lldb/Utility/State.h" - -#include "Plugins/Process/Utility/UnwindLLDB.h" -#include "ProcessWindows.h" -#include "ProcessWindowsLog.h" -#include "TargetThreadWindows.h" - -#if defined(_WIN64) -#include "x64/RegisterContextWindows_x64.h" -#else -#include "x86/RegisterContextWindows_x86.h" -#endif - -using namespace lldb; -using namespace lldb_private; - -TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, - const HostThread &thread) - : Thread(process, thread.GetNativeThread().GetThreadId()), - m_thread_reg_ctx_sp(), m_host_thread(thread) {} - -TargetThreadWindows::~TargetThreadWindows() { DestroyThread(); } - -void TargetThreadWindows::RefreshStateAfterStop() { - ::SuspendThread(m_host_thread.GetNativeThread().GetSystemHandle()); - SetState(eStateStopped); - GetRegisterContext()->InvalidateIfNeeded(false); -} - -void TargetThreadWindows::WillResume(lldb::StateType resume_state) {} - -void TargetThreadWindows::DidStop() {} - -RegisterContextSP TargetThreadWindows::GetRegisterContext() { - if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrame(nullptr); - - return m_reg_context_sp; -} - -RegisterContextSP -TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame) { - RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) { - if (!m_thread_reg_ctx_sp) { - ArchSpec arch = HostInfo::GetArchitecture(); - switch (arch.GetMachine()) { - case llvm::Triple::x86: -#if defined(_WIN64) - // FIXME: This is a Wow64 process, create a RegisterContextWindows_Wow64 - LLDB_LOG(log, "This is a Wow64 process, we should create a " - "RegisterContextWindows_Wow64, but we don't."); -#else - m_thread_reg_ctx_sp.reset( - new RegisterContextWindows_x86(*this, concrete_frame_idx)); -#endif - break; - case llvm::Triple::x86_64: -#if defined(_WIN64) - m_thread_reg_ctx_sp.reset( - new RegisterContextWindows_x64(*this, concrete_frame_idx)); -#else - LLDB_LOG(log, "LLDB is 32-bit, but the target process is 64-bit."); -#endif - default: - break; - } - } - reg_ctx_sp = m_thread_reg_ctx_sp; - } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); - } - - return reg_ctx_sp; -} - -bool TargetThreadWindows::CalculateStopInfo() { - SetStopInfo(m_stop_info_sp); - return true; -} - -Unwind *TargetThreadWindows::GetUnwinder() { - // FIXME: Implement an unwinder based on the Windows unwinder exposed through - // DIA SDK. - if (!m_unwinder_ap) - m_unwinder_ap.reset(new UnwindLLDB(*this)); - return m_unwinder_ap.get(); -} - -Status TargetThreadWindows::DoResume() { - StateType resume_state = GetTemporaryResumeState(); - StateType current_state = GetState(); - if (resume_state == current_state) - return Status(); - - if (resume_state == eStateStepping) { - uint32_t flags_index = - GetRegisterContext()->ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - uint64_t flags_value = - GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0); - flags_value |= 0x100; // Set the trap flag on the CPU - GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value); - } - - if (resume_state == eStateStepping || resume_state == eStateRunning) { - DWORD previous_suspend_count = 0; - HANDLE thread_handle = m_host_thread.GetNativeThread().GetSystemHandle(); - do { - // ResumeThread returns -1 on error, or the thread's *previous* suspend - // count on success. This means that the return value is 1 when the thread - // was restarted. Note that DWORD is an unsigned int, so we need to - // explicitly compare with -1. - previous_suspend_count = ::ResumeThread(thread_handle); - - if (previous_suspend_count == (DWORD)-1) - return Status(::GetLastError(), eErrorTypeWin32); - - } while (previous_suspend_count > 1); - } - - return Status(); -} diff --git a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h b/source/Plugins/Process/Windows/Common/TargetThreadWindows.h deleted file mode 100644 index 952c0f55b57f3..0000000000000 --- a/source/Plugins/Process/Windows/Common/TargetThreadWindows.h +++ /dev/null @@ -1,50 +0,0 @@ -//===-- TargetThreadWindows.h -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Plugins_Process_Windows_TargetThreadWindows_H_ -#define liblldb_Plugins_Process_Windows_TargetThreadWindows_H_ - -//#include "ForwardDecl.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Target/Thread.h" -#include "lldb/lldb-forward.h" - -#include "RegisterContextWindows.h" - -namespace lldb_private { -class ProcessWindows; -class HostThread; -class StackFrame; - -class TargetThreadWindows : public lldb_private::Thread { -public: - TargetThreadWindows(ProcessWindows &process, const HostThread &thread); - virtual ~TargetThreadWindows(); - - // lldb_private::Thread overrides - void RefreshStateAfterStop() override; - void WillResume(lldb::StateType resume_state) override; - void DidStop() override; - lldb::RegisterContextSP GetRegisterContext() override; - lldb::RegisterContextSP - CreateRegisterContextForFrame(StackFrame *frame) override; - bool CalculateStopInfo() override; - Unwind *GetUnwinder() override; - - Status DoResume(); - - HostThread GetHostThread() const { return m_host_thread; } - -private: - lldb::RegisterContextSP m_thread_reg_ctx_sp; - HostThread m_host_thread; -}; -} // namespace lldb_private - -#endif diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp deleted file mode 100644 index 584136a6e5bb4..0000000000000 --- a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp +++ /dev/null @@ -1,341 +0,0 @@ -//===-- RegisterContextWindows_x64.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/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-private-types.h" - -#include "RegisterContextWindows_x64.h" -#include "Plugins/Process/Utility/RegisterContext_x86.h" -#include "TargetThreadWindows.h" -#include "Plugins/Process/Utility/lldb-x86-register-enums.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -#define DEFINE_GPR(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatHexUppercase -#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 8, 0, eEncodingUint, eFormatBinary - -namespace { - -// This enum defines the layout of the global RegisterInfo array. This is -// necessary because lldb register sets are defined in terms of indices into -// the register array. As such, the order of RegisterInfos defined in global -// registers array must match the order defined here. When defining the -// register set layouts, these values can appear in an arbitrary order, and -// that determines the order that register values are displayed in a dump. -enum RegisterIndex { - eRegisterIndexRax, - eRegisterIndexRbx, - eRegisterIndexRcx, - eRegisterIndexRdx, - eRegisterIndexRdi, - eRegisterIndexRsi, - eRegisterIndexRbp, - eRegisterIndexRsp, - eRegisterIndexR8, - eRegisterIndexR9, - eRegisterIndexR10, - eRegisterIndexR11, - eRegisterIndexR12, - eRegisterIndexR13, - eRegisterIndexR14, - eRegisterIndexR15, - eRegisterIndexRip, - eRegisterIndexRflags -}; - -// Array of all register information supported by Windows x86 -RegisterInfo g_register_infos[] = { - // Macro auto defines most stuff eh_frame DWARF - // GENERIC - // GDB LLDB VALUE REGS INVALIDATE REGS - // ================================ ========================= - // ====================== ========================= - // =================== ================= ========== =============== - {DEFINE_GPR(rax, nullptr), - {dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_rax_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rbx, nullptr), - {dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_rbx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rcx, nullptr), - {dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG1, - LLDB_INVALID_REGNUM, lldb_rcx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rdx, nullptr), - {dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG2, - LLDB_INVALID_REGNUM, lldb_rdx_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rdi, nullptr), - {dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_rdi_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rsi, nullptr), - {dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_rsi_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rbp, "fp"), - {dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, - LLDB_INVALID_REGNUM, lldb_rbp_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rsp, "sp"), - {dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM, lldb_rsp_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r8, nullptr), - {dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG3, - LLDB_INVALID_REGNUM, lldb_r8_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r9, nullptr), - {dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG4, - LLDB_INVALID_REGNUM, lldb_r9_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r10, nullptr), - {dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_REGNUM_GENERIC_ARG5, - LLDB_INVALID_REGNUM, lldb_r10_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r11, nullptr), - {dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_REGNUM_GENERIC_ARG6, - LLDB_INVALID_REGNUM, lldb_r11_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r12, nullptr), - {dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_r12_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r13, nullptr), - {dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_r13_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r14, nullptr), - {dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_r14_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(r15, nullptr), - {dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_r15_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR(rip, "pc"), - {dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, - LLDB_INVALID_REGNUM, lldb_rip_x86_64}, - nullptr, - nullptr}, - {DEFINE_GPR_BIN(eflags, "flags"), - {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, lldb_rflags_x86_64}, - nullptr, - nullptr}, -}; - -static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); - -// Array of lldb register numbers used to define the set of all General Purpose -// Registers -uint32_t g_gpr_reg_indices[] = { - eRegisterIndexRax, eRegisterIndexRbx, eRegisterIndexRcx, - eRegisterIndexRdx, eRegisterIndexRdi, eRegisterIndexRsi, - eRegisterIndexRbp, eRegisterIndexRsp, eRegisterIndexR8, - eRegisterIndexR9, eRegisterIndexR10, eRegisterIndexR11, - eRegisterIndexR12, eRegisterIndexR13, eRegisterIndexR14, - eRegisterIndexR15, eRegisterIndexRip, eRegisterIndexRflags}; - -RegisterSet g_register_sets[] = { - {"General Purpose Registers", "gpr", - llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, -}; -} - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows_x64::RegisterContextWindows_x64( - Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows(thread, concrete_frame_idx) {} - -RegisterContextWindows_x64::~RegisterContextWindows_x64() {} - -size_t RegisterContextWindows_x64::GetRegisterCount() { - return llvm::array_lengthof(g_register_infos); -} - -const RegisterInfo * -RegisterContextWindows_x64::GetRegisterInfoAtIndex(size_t reg) { - if (reg < k_num_register_infos) - return &g_register_infos[reg]; - return NULL; -} - -size_t RegisterContextWindows_x64::GetRegisterSetCount() { - return llvm::array_lengthof(g_register_sets); -} - -const RegisterSet *RegisterContextWindows_x64::GetRegisterSet(size_t reg_set) { - return &g_register_sets[reg_set]; -} - -bool RegisterContextWindows_x64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - if (!CacheAllRegisterValues()) - return false; - - if (reg_info == nullptr) - return false; - - switch (reg_info->kinds[eRegisterKindLLDB]) { - case lldb_rax_x86_64: - reg_value.SetUInt64(m_context.Rax); - break; - case lldb_rbx_x86_64: - reg_value.SetUInt64(m_context.Rbx); - break; - case lldb_rcx_x86_64: - reg_value.SetUInt64(m_context.Rcx); - break; - case lldb_rdx_x86_64: - reg_value.SetUInt64(m_context.Rdx); - break; - case lldb_rdi_x86_64: - reg_value.SetUInt64(m_context.Rdi); - break; - case lldb_rsi_x86_64: - reg_value.SetUInt64(m_context.Rsi); - break; - case lldb_r8_x86_64: - reg_value.SetUInt64(m_context.R8); - break; - case lldb_r9_x86_64: - reg_value.SetUInt64(m_context.R9); - break; - case lldb_r10_x86_64: - reg_value.SetUInt64(m_context.R10); - break; - case lldb_r11_x86_64: - reg_value.SetUInt64(m_context.R11); - break; - case lldb_r12_x86_64: - reg_value.SetUInt64(m_context.R12); - break; - case lldb_r13_x86_64: - reg_value.SetUInt64(m_context.R13); - break; - case lldb_r14_x86_64: - reg_value.SetUInt64(m_context.R14); - break; - case lldb_r15_x86_64: - reg_value.SetUInt64(m_context.R15); - break; - case lldb_rbp_x86_64: - reg_value.SetUInt64(m_context.Rbp); - break; - case lldb_rsp_x86_64: - reg_value.SetUInt64(m_context.Rsp); - break; - case lldb_rip_x86_64: - reg_value.SetUInt64(m_context.Rip); - break; - case lldb_rflags_x86_64: - reg_value.SetUInt64(m_context.EFlags); - break; - } - return true; -} - -bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we - // need to make sure our cached copy of the register values are fresh. - // Otherwise when writing EAX, for example, we may also overwrite some other - // register with a stale value. - if (!CacheAllRegisterValues()) - return false; - - switch (reg_info->kinds[eRegisterKindLLDB]) { - case lldb_rax_x86_64: - m_context.Rax = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_context.Rbx = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_context.Rcx = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_context.Rdx = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_context.Rdi = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_context.Rsi = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_context.R8 = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_context.R9 = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_context.R10 = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_context.R11 = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_context.R12 = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_context.R13 = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_context.R14 = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_context.R15 = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_context.Rbp = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_context.Rsp = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_context.Rip = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_context.EFlags = reg_value.GetAsUInt64(); - break; - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} diff --git a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h b/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h deleted file mode 100644 index 62cedc8fbab04..0000000000000 --- a/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h +++ /dev/null @@ -1,48 +0,0 @@ -//===-- RegisterContextWindows_x64.h ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextWindows_x64_H_ -#define liblldb_RegisterContextWindows_x64_H_ - -#include "RegisterContextWindows.h" -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class Thread; - -class RegisterContextWindows_x64 : public RegisterContextWindows { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows_x64(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows_x64(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - size_t GetRegisterCount() override; - - const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - - size_t GetRegisterSetCount() override; - - const RegisterSet *GetRegisterSet(size_t reg_set) override; - - bool ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - bool WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; -}; -} - -#endif // #ifndef liblldb_RegisterContextWindows_x64_H_ diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp deleted file mode 100644 index e012f9105f31a..0000000000000 --- a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ /dev/null @@ -1,287 +0,0 @@ -//===-- RegisterContextWindows_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/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-private-types.h" - -#include "ProcessWindowsLog.h" -#include "RegisterContextWindows_x86.h" -#include "Plugins/Process/Utility/RegisterContext_x86.h" -#include "TargetThreadWindows.h" -#include "Plugins/Process/Utility/lldb-x86-register-enums.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -#define DEFINE_GPR(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatHexUppercase -#define DEFINE_GPR_BIN(reg, alt) #reg, alt, 4, 0, eEncodingUint, eFormatBinary - -namespace { - -// This enum defines the layout of the global RegisterInfo array. This is -// necessary because lldb register sets are defined in terms of indices into -// the register array. As such, the order of RegisterInfos defined in global -// registers array must match the order defined here. When defining the -// register set layouts, these values can appear in an arbitrary order, and -// that determines the order that register values are displayed in a dump. -enum RegisterIndex { - eRegisterIndexEax, - eRegisterIndexEbx, - eRegisterIndexEcx, - eRegisterIndexEdx, - eRegisterIndexEdi, - eRegisterIndexEsi, - eRegisterIndexEbp, - eRegisterIndexEsp, - eRegisterIndexEip, - eRegisterIndexEflags -}; - -// Array of all register information supported by Windows x86 -RegisterInfo g_register_infos[] = { - // Macro auto defines most stuff eh_frame DWARF - // GENERIC GDB LLDB - // VALUE REGS INVALIDATE REGS - // ============================== ======================= - // =================== ========================= =================== - // ================= ========== =============== - {DEFINE_GPR(eax, nullptr), - {ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_eax_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(ebx, nullptr), - {ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_ebx_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(ecx, nullptr), - {ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_ecx_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(edx, nullptr), - {ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_edx_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(edi, nullptr), - {ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_edi_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(esi, nullptr), - {ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM, lldb_esi_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(ebp, "fp"), - {ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, - LLDB_INVALID_REGNUM, lldb_ebp_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(esp, "sp"), - {ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, - LLDB_INVALID_REGNUM, lldb_esp_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR(eip, "pc"), - {ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, - LLDB_INVALID_REGNUM, lldb_eip_i386}, - nullptr, - nullptr, - nullptr, - 0u}, - {DEFINE_GPR_BIN(eflags, "flags"), - {ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, - LLDB_INVALID_REGNUM, lldb_eflags_i386}, - nullptr, - nullptr, - nullptr, - 0u}, -}; -static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); - -// Array of lldb register numbers used to define the set of all General Purpose -// Registers -uint32_t g_gpr_reg_indices[] = {eRegisterIndexEax, eRegisterIndexEbx, - eRegisterIndexEcx, eRegisterIndexEdx, - eRegisterIndexEdi, eRegisterIndexEsi, - eRegisterIndexEbp, eRegisterIndexEsp, - eRegisterIndexEip, eRegisterIndexEflags}; - -RegisterSet g_register_sets[] = { - {"General Purpose Registers", "gpr", - llvm::array_lengthof(g_gpr_reg_indices), g_gpr_reg_indices}, -}; -} - -//------------------------------------------------------------------ -// Constructors and Destructors -//------------------------------------------------------------------ -RegisterContextWindows_x86::RegisterContextWindows_x86( - Thread &thread, uint32_t concrete_frame_idx) - : RegisterContextWindows(thread, concrete_frame_idx) {} - -RegisterContextWindows_x86::~RegisterContextWindows_x86() {} - -size_t RegisterContextWindows_x86::GetRegisterCount() { - return llvm::array_lengthof(g_register_infos); -} - -const RegisterInfo * -RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg) { - if (reg < k_num_register_infos) - return &g_register_infos[reg]; - return NULL; -} - -size_t RegisterContextWindows_x86::GetRegisterSetCount() { - return llvm::array_lengthof(g_register_sets); -} - -const RegisterSet *RegisterContextWindows_x86::GetRegisterSet(size_t reg_set) { - return &g_register_sets[reg_set]; -} - -bool RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - if (!CacheAllRegisterValues()) - return false; - - if (reg_info == nullptr) - return false; - - uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - switch (reg) { - case lldb_eax_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "EAX", m_context.Eax, reg_value); - case lldb_ebx_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "EBX", m_context.Ebx, reg_value); - case lldb_ecx_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "ECX", m_context.Ecx, reg_value); - case lldb_edx_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "EDX", m_context.Edx, reg_value); - case lldb_edi_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "EDI", m_context.Edi, reg_value); - case lldb_esi_i386: - return ReadRegisterHelper(CONTEXT_INTEGER, "ESI", m_context.Esi, reg_value); - case lldb_ebp_i386: - return ReadRegisterHelper(CONTEXT_CONTROL, "EBP", m_context.Ebp, reg_value); - case lldb_esp_i386: - return ReadRegisterHelper(CONTEXT_CONTROL, "ESP", m_context.Esp, reg_value); - case lldb_eip_i386: - return ReadRegisterHelper(CONTEXT_CONTROL, "EIP", m_context.Eip, reg_value); - case lldb_eflags_i386: - return ReadRegisterHelper(CONTEXT_CONTROL, "EFLAGS", m_context.EFlags, - reg_value); - default: - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); - LLDB_LOG(log, "Requested unknown register {0}", reg); - break; - } - return false; -} - -bool RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) { - // Since we cannot only write a single register value to the inferior, we - // need to make sure our cached copy of the register values are fresh. - // Otherwise when writing EAX, for example, we may also overwrite some other - // register with a stale value. - if (!CacheAllRegisterValues()) - return false; - - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); - uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - switch (reg) { - case lldb_eax_i386: - LLDB_LOG(log, "Write value {0:x} to EAX", reg_value.GetAsUInt32()); - m_context.Eax = reg_value.GetAsUInt32(); - break; - case lldb_ebx_i386: - LLDB_LOG(log, "Write value {0:x} to EBX", reg_value.GetAsUInt32()); - m_context.Ebx = reg_value.GetAsUInt32(); - break; - case lldb_ecx_i386: - LLDB_LOG(log, "Write value {0:x} to ECX", reg_value.GetAsUInt32()); - m_context.Ecx = reg_value.GetAsUInt32(); - break; - case lldb_edx_i386: - LLDB_LOG(log, "Write value {0:x} to EDX", reg_value.GetAsUInt32()); - m_context.Edx = reg_value.GetAsUInt32(); - break; - case lldb_edi_i386: - LLDB_LOG(log, "Write value {0:x} to EDI", reg_value.GetAsUInt32()); - m_context.Edi = reg_value.GetAsUInt32(); - break; - case lldb_esi_i386: - LLDB_LOG(log, "Write value {0:x} to ESI", reg_value.GetAsUInt32()); - m_context.Esi = reg_value.GetAsUInt32(); - break; - case lldb_ebp_i386: - LLDB_LOG(log, "Write value {0:x} to EBP", reg_value.GetAsUInt32()); - m_context.Ebp = reg_value.GetAsUInt32(); - break; - case lldb_esp_i386: - LLDB_LOG(log, "Write value {0:x} to ESP", reg_value.GetAsUInt32()); - m_context.Esp = reg_value.GetAsUInt32(); - break; - case lldb_eip_i386: - LLDB_LOG(log, "Write value {0:x} to EIP", reg_value.GetAsUInt32()); - m_context.Eip = reg_value.GetAsUInt32(); - break; - case lldb_eflags_i386: - LLDB_LOG(log, "Write value {0:x} to EFLAGS", reg_value.GetAsUInt32()); - m_context.EFlags = reg_value.GetAsUInt32(); - break; - default: - LLDB_LOG(log, "Write value {0:x} to unknown register {1}", - reg_value.GetAsUInt32(), reg); - } - - // Physically update the registers in the target process. - TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread); - return ::SetThreadContext( - wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); -} - -bool RegisterContextWindows_x86::ReadRegisterHelper( - DWORD flags_required, const char *reg_name, DWORD value, - RegisterValue ®_value) const { - Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_REGISTERS); - if ((m_context.ContextFlags & flags_required) != flags_required) { - LLDB_LOG(log, "Thread context doesn't have {0}", reg_name); - return false; - } - LLDB_LOG(log, "Read value {0:x} from {1}", value, reg_name); - reg_value.SetUInt32(value); - return true; -} diff --git a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h b/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h deleted file mode 100644 index aae645fdb5a3e..0000000000000 --- a/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h +++ /dev/null @@ -1,52 +0,0 @@ -//===-- RegisterContextWindows_x86.h ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextWindows_x86_H_ -#define liblldb_RegisterContextWindows_x86_H_ - -#include "RegisterContextWindows.h" -#include "lldb/lldb-forward.h" - -namespace lldb_private { - -class Thread; - -class RegisterContextWindows_x86 : public RegisterContextWindows { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx); - - virtual ~RegisterContextWindows_x86(); - - //------------------------------------------------------------------ - // Subclasses must override these functions - //------------------------------------------------------------------ - size_t GetRegisterCount() override; - - const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; - - size_t GetRegisterSetCount() override; - - const RegisterSet *GetRegisterSet(size_t reg_set) override; - - bool ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) override; - - bool WriteRegister(const RegisterInfo *reg_info, - const RegisterValue ®_value) override; - -private: - bool ReadRegisterHelper(DWORD flags_required, const char *reg_name, - DWORD value, RegisterValue ®_value) const; -}; -} - -#endif // #ifndef liblldb_RegisterContextWindows_x86_H_ diff --git a/source/Plugins/Process/elf-core/CMakeLists.txt b/source/Plugins/Process/elf-core/CMakeLists.txt deleted file mode 100644 index 9b6739824c066..0000000000000 --- a/source/Plugins/Process/elf-core/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -add_lldb_library(lldbPluginProcessElfCore PLUGIN - ProcessElfCore.cpp - ThreadElfCore.cpp - RegisterContextPOSIXCore_arm.cpp - RegisterContextPOSIXCore_arm64.cpp - RegisterContextPOSIXCore_mips64.cpp - RegisterContextPOSIXCore_powerpc.cpp - RegisterContextPOSIXCore_ppc64le.cpp - RegisterContextPOSIXCore_s390x.cpp - RegisterContextPOSIXCore_x86_64.cpp - RegisterUtilities.cpp - - LINK_LIBS - lldbCore - lldbTarget - lldbPluginDynamicLoaderPosixDYLD - lldbPluginObjectFileELF - lldbPluginProcessUtility - LINK_COMPONENTS - BinaryFormat - Support - ) diff --git a/source/Plugins/Process/gdb-remote/CMakeLists.txt b/source/Plugins/Process/gdb-remote/CMakeLists.txt deleted file mode 100644 index 4eb5291d54d5a..0000000000000 --- a/source/Plugins/Process/gdb-remote/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -if (CMAKE_SYSTEM_NAME MATCHES "Darwin") - include_directories(${LIBXML2_INCLUDE_DIR}) -endif() - -set(LLDB_PLUGINS - lldbPluginProcessUtility - lldbPluginPlatformMacOSX -) - -if(HAVE_LIBCOMPRESSION) - set(LIBCOMPRESSION compression) -endif() - -add_lldb_library(lldbPluginProcessGDBRemote PLUGIN - GDBRemoteClientBase.cpp - GDBRemoteCommunication.cpp - GDBRemoteCommunicationClient.cpp - GDBRemoteCommunicationHistory.cpp - GDBRemoteCommunicationReplayServer.cpp - GDBRemoteCommunicationServer.cpp - GDBRemoteCommunicationServerCommon.cpp - GDBRemoteCommunicationServerLLGS.cpp - GDBRemoteCommunicationServerPlatform.cpp - GDBRemoteRegisterContext.cpp - ProcessGDBRemote.cpp - ProcessGDBRemoteLog.cpp - ThreadGDBRemote.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbDataFormatters - lldbHost - lldbInterpreter - lldbSymbol - lldbTarget - lldbUtility - ${LLDB_PLUGINS} - ${LIBCOMPRESSION} - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/mach-core/CMakeLists.txt b/source/Plugins/Process/mach-core/CMakeLists.txt deleted file mode 100644 index e79cd82c92a67..0000000000000 --- a/source/Plugins/Process/mach-core/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_lldb_library(lldbPluginProcessMachCore PLUGIN - ProcessMachCore.cpp - ThreadMachCore.cpp - - LINK_LIBS - lldbBreakpoint - lldbCore - lldbHost - lldbSymbol - lldbTarget - lldbUtility - lldbPluginDynamicLoaderDarwinKernel - lldbPluginDynamicLoaderMacOSXDYLD - lldbPluginObjectFileMachO - LINK_COMPONENTS - Support - ) diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/source/Plugins/Process/mach-core/ProcessMachCore.cpp deleted file mode 100644 index 08b9f08a47f67..0000000000000 --- a/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ /dev/null @@ -1,635 +0,0 @@ -//===-- ProcessMachCore.cpp ------------------------------------------*- C++ -//-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <errno.h> -#include <stdlib.h> - -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/Threading.h" -#include <mutex> - -#include "lldb/Core/Debugger.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/Section.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/MemoryRegionInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Utility/DataBuffer.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/State.h" - -#include "ProcessMachCore.h" -#include "Plugins/Process/Utility/StopInfoMachException.h" -#include "ThreadMachCore.h" - -// Needed for the plug-in names for the dynamic loaders. -#include "lldb/Host/SafeMachO.h" - -#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" -#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" -#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" - -using namespace lldb; -using namespace lldb_private; - -ConstString ProcessMachCore::GetPluginNameStatic() { - static ConstString g_name("mach-o-core"); - return g_name; -} - -const char *ProcessMachCore::GetPluginDescriptionStatic() { - return "Mach-O core file debugging plug-in."; -} - -void ProcessMachCore::Terminate() { - PluginManager::UnregisterPlugin(ProcessMachCore::CreateInstance); -} - -lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp, - ListenerSP listener_sp, - const FileSpec *crash_file) { - lldb::ProcessSP process_sp; - if (crash_file) { - const size_t header_size = sizeof(llvm::MachO::mach_header); - auto data_sp = FileSystem::Instance().CreateDataBuffer( - crash_file->GetPath(), header_size, 0); - if (data_sp && data_sp->GetByteSize() == header_size) { - DataExtractor data(data_sp, lldb::eByteOrderLittle, 4); - - lldb::offset_t data_offset = 0; - llvm::MachO::mach_header mach_header; - if (ObjectFileMachO::ParseHeader(data, &data_offset, mach_header)) { - if (mach_header.filetype == llvm::MachO::MH_CORE) - process_sp.reset( - new ProcessMachCore(target_sp, listener_sp, *crash_file)); - } - } - } - return process_sp; -} - -bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) { - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) { - // Don't add the Target's architecture to the ModuleSpec - we may be - // working with a core file that doesn't have the correct cpusubtype in the - // header but we should still try to use it - - // ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach. - ModuleSpec core_module_spec(m_core_file); - Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp, - NULL, NULL, NULL)); - - if (m_core_module_sp) { - ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); - if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile) - return true; - } - } - return false; -} - -//---------------------------------------------------------------------- -// ProcessMachCore constructor -//---------------------------------------------------------------------- -ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp, - ListenerSP listener_sp, - const FileSpec &core_file) - : Process(target_sp, listener_sp), m_core_aranges(), m_core_range_infos(), - m_core_module_sp(), m_core_file(core_file), - m_dyld_addr(LLDB_INVALID_ADDRESS), - m_mach_kernel_addr(LLDB_INVALID_ADDRESS), m_dyld_plugin_name() {} - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -ProcessMachCore::~ProcessMachCore() { - Clear(); - // We need to call finalize on the process before destroying ourselves to - // make sure all of the broadcaster cleanup goes as planned. If we destruct - // this class, then Process::~Process() might have problems trying to fully - // destroy the broadcaster. - Finalize(); -} - -//---------------------------------------------------------------------- -// PluginInterface -//---------------------------------------------------------------------- -ConstString ProcessMachCore::GetPluginName() { return GetPluginNameStatic(); } - -uint32_t ProcessMachCore::GetPluginVersion() { return 1; } - -bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | - LIBLLDB_LOG_PROCESS)); - llvm::MachO::mach_header header; - Status error; - if (DoReadMemory(addr, &header, sizeof(header), error) != sizeof(header)) - return false; - if (header.magic == llvm::MachO::MH_CIGAM || - header.magic == llvm::MachO::MH_CIGAM_64) { - header.magic = llvm::ByteSwap_32(header.magic); - header.cputype = llvm::ByteSwap_32(header.cputype); - header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype); - header.filetype = llvm::ByteSwap_32(header.filetype); - header.ncmds = llvm::ByteSwap_32(header.ncmds); - header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds); - header.flags = llvm::ByteSwap_32(header.flags); - } - - // TODO: swap header if needed... - // printf("0x%16.16" PRIx64 ": magic = 0x%8.8x, file_type= %u\n", vaddr, - // header.magic, header.filetype); - if (header.magic == llvm::MachO::MH_MAGIC || - header.magic == llvm::MachO::MH_MAGIC_64) { - // Check MH_EXECUTABLE to see if we can find the mach image that contains - // the shared library list. The dynamic loader (dyld) is what contains the - // list for user applications, and the mach kernel contains a global that - // has the list of kexts to load - switch (header.filetype) { - case llvm::MachO::MH_DYLINKER: - // printf("0x%16.16" PRIx64 ": file_type = MH_DYLINKER\n", vaddr); - // Address of dyld "struct mach_header" in the core file - if (log) - log->Printf("ProcessMachCore::GetDynamicLoaderAddress found a user " - "process dyld binary image at 0x%" PRIx64, - addr); - m_dyld_addr = addr; - return true; - - case llvm::MachO::MH_EXECUTE: - // printf("0x%16.16" PRIx64 ": file_type = MH_EXECUTE\n", vaddr); - // Check MH_EXECUTABLE file types to see if the dynamic link object flag - // is NOT set. If it isn't, then we have a mach_kernel. - if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) { - if (log) - log->Printf("ProcessMachCore::GetDynamicLoaderAddress found a mach " - "kernel binary image at 0x%" PRIx64, - addr); - // Address of the mach kernel "struct mach_header" in the core file. - m_mach_kernel_addr = addr; - return true; - } - break; - } - } - return false; -} - -//---------------------------------------------------------------------- -// Process Control -//---------------------------------------------------------------------- -Status ProcessMachCore::DoLoadCore() { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | - LIBLLDB_LOG_PROCESS)); - Status error; - if (!m_core_module_sp) { - error.SetErrorString("invalid core module"); - return error; - } - - ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); - if (core_objfile == NULL) { - error.SetErrorString("invalid core object file"); - return error; - } - - if (core_objfile->GetNumThreadContexts() == 0) { - error.SetErrorString("core file doesn't contain any LC_THREAD load " - "commands, or the LC_THREAD architecture is not " - "supported in this lldb"); - return error; - } - - SectionList *section_list = core_objfile->GetSectionList(); - if (section_list == NULL) { - error.SetErrorString("core file has no sections"); - return error; - } - - const uint32_t num_sections = section_list->GetNumSections(0); - if (num_sections == 0) { - error.SetErrorString("core file has no sections"); - return error; - } - - SetCanJIT(false); - - llvm::MachO::mach_header header; - DataExtractor data(&header, sizeof(header), - m_core_module_sp->GetArchitecture().GetByteOrder(), - m_core_module_sp->GetArchitecture().GetAddressByteSize()); - - bool ranges_are_sorted = true; - addr_t vm_addr = 0; - for (uint32_t i = 0; i < num_sections; ++i) { - Section *section = section_list->GetSectionAtIndex(i).get(); - if (section) { - lldb::addr_t section_vm_addr = section->GetFileAddress(); - FileRange file_range(section->GetFileOffset(), section->GetFileSize()); - VMRangeToFileOffset::Entry range_entry( - section_vm_addr, section->GetByteSize(), file_range); - - if (vm_addr > section_vm_addr) - ranges_are_sorted = false; - vm_addr = section->GetFileAddress(); - VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); - // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - - // 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", - // i, - // range_entry.GetRangeBase(), - // range_entry.GetRangeEnd(), - // range_entry.data.GetRangeBase(), - // range_entry.data.GetRangeEnd()); - - if (last_entry && - last_entry->GetRangeEnd() == range_entry.GetRangeBase() && - last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { - last_entry->SetRangeEnd(range_entry.GetRangeEnd()); - last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd()); - // puts("combine"); - } else { - m_core_aranges.Append(range_entry); - } - // Some core files don't fill in the permissions correctly. If that is - // the case assume read + execute so clients don't think the memory is - // not readable, or executable. The memory isn't writable since this - // plug-in doesn't implement DoWriteMemory. - uint32_t permissions = section->GetPermissions(); - if (permissions == 0) - permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; - m_core_range_infos.Append(VMRangeToPermissions::Entry( - section_vm_addr, section->GetByteSize(), permissions)); - } - } - if (!ranges_are_sorted) { - m_core_aranges.Sort(); - m_core_range_infos.Sort(); - } - - - bool found_main_binary_definitively = false; - - addr_t objfile_binary_addr; - UUID objfile_binary_uuid; - if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid)) - { - if (objfile_binary_addr != LLDB_INVALID_ADDRESS) - { - m_mach_kernel_addr = objfile_binary_addr; - found_main_binary_definitively = true; - if (log) - log->Printf ("ProcessMachCore::DoLoadCore: using kernel address 0x%" PRIx64 - " from LC_NOTE 'main bin spec' load command.", m_mach_kernel_addr); - } - } - - // This checks for the presence of an LC_IDENT string in a core file; - // LC_IDENT is very obsolete and should not be used in new code, but if the - // load command is present, let's use the contents. - std::string corefile_identifier = core_objfile->GetIdentifierString(); - if (!found_main_binary_definitively && - corefile_identifier.find("Darwin Kernel") != std::string::npos) { - UUID uuid; - addr_t addr = LLDB_INVALID_ADDRESS; - if (corefile_identifier.find("UUID=") != std::string::npos) { - size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); - std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); - } - if (corefile_identifier.find("stext=") != std::string::npos) { - size_t p = corefile_identifier.find("stext=") + strlen("stext="); - if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') { - errno = 0; - addr = ::strtoul(corefile_identifier.c_str() + p, NULL, 16); - if (errno != 0 || addr == 0) - addr = LLDB_INVALID_ADDRESS; - } - } - if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) { - m_mach_kernel_addr = addr; - found_main_binary_definitively = true; - if (log) - log->Printf( - "ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64 - " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", - addr, corefile_identifier.c_str()); - } - } - - if (!found_main_binary_definitively && - (m_dyld_addr == LLDB_INVALID_ADDRESS || - m_mach_kernel_addr == LLDB_INVALID_ADDRESS)) { - // We need to locate the main executable in the memory ranges we have in - // the core file. We need to search for both a user-process dyld binary - // and a kernel binary in memory; we must look at all the pages in the - // binary so we don't miss one or the other. Step through all memory - // segments searching for a kernel binary and for a user process dyld -- - // we'll decide which to prefer later if both are present. - - const size_t num_core_aranges = m_core_aranges.GetSize(); - for (size_t i = 0; i < num_core_aranges; ++i) { - const VMRangeToFileOffset::Entry *entry = - m_core_aranges.GetEntryAtIndex(i); - lldb::addr_t section_vm_addr_start = entry->GetRangeBase(); - lldb::addr_t section_vm_addr_end = entry->GetRangeEnd(); - for (lldb::addr_t section_vm_addr = section_vm_addr_start; - section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { - GetDynamicLoaderAddress(section_vm_addr); - } - } - } - - if (!found_main_binary_definitively && - m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - // In the case of multiple kernel images found in the core file via - // exhaustive search, we may not pick the correct one. See if the - // DynamicLoaderDarwinKernel's search heuristics might identify the correct - // one. Most of the time, I expect the address from SearchForDarwinKernel() - // will be the same as the address we found via exhaustive search. - - if (!GetTarget().GetArchitecture().IsValid() && m_core_module_sp.get()) { - GetTarget().SetArchitecture(m_core_module_sp->GetArchitecture()); - } - - // SearchForDarwinKernel will end up calling back into this this class in - // the GetImageInfoAddress method which will give it the - // m_mach_kernel_addr/m_dyld_addr it already has. Save that aside and set - // m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so - // DynamicLoaderDarwinKernel does a real search for the kernel using its - // own heuristics. - - addr_t saved_mach_kernel_addr = m_mach_kernel_addr; - addr_t saved_user_dyld_addr = m_dyld_addr; - m_mach_kernel_addr = LLDB_INVALID_ADDRESS; - m_dyld_addr = LLDB_INVALID_ADDRESS; - - addr_t better_kernel_address = - DynamicLoaderDarwinKernel::SearchForDarwinKernel(this); - - m_mach_kernel_addr = saved_mach_kernel_addr; - m_dyld_addr = saved_user_dyld_addr; - - if (better_kernel_address != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using the kernel address " - "from DynamicLoaderDarwinKernel"); - m_mach_kernel_addr = better_kernel_address; - } - } - - // If we found both a user-process dyld and a kernel binary, we need to - // decide which to prefer. - if (GetCorefilePreference() == eKernelCorefile) { - if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } - } else { - if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - if (log) - log->Printf("ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - } - } - - if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) { - // For non-user process core files, the permissions on the core file - // segments are usually meaningless, they may be just "read", because we're - // dealing with kernel coredumps or early startup coredumps and the dumper - // is grabbing pages of memory without knowing what they are. If they - // aren't marked as "exeuctable", that can break the unwinder which will - // check a pc value to see if it is in an executable segment and stop the - // backtrace early if it is not ("executable" and "unknown" would both be - // fine, but "not executable" will break the unwinder). - size_t core_range_infos_size = m_core_range_infos.GetSize(); - for (size_t i = 0; i < core_range_infos_size; i++) { - VMRangeToPermissions::Entry *ent = - m_core_range_infos.GetMutableEntryAtIndex(i); - ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; - } - } - - // Even if the architecture is set in the target, we need to override it to - // match the core file which is always single arch. - ArchSpec arch(m_core_module_sp->GetArchitecture()); - if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) { - arch = Platform::GetAugmentedArchSpec(GetTarget().GetPlatform().get(), "i386"); - } - if (arch.IsValid()) - GetTarget().SetArchitecture(arch); - - return error; -} - -lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() { - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset(DynamicLoader::FindPlugin( - this, - m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString())); - return m_dyld_ap.get(); -} - -bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { - if (old_thread_list.GetSize(false) == 0) { - // Make up the thread the first time this is called so we can setup our one - // and only core thread state. - ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); - - if (core_objfile) { - const uint32_t num_threads = core_objfile->GetNumThreadContexts(); - for (lldb::tid_t tid = 0; tid < num_threads; ++tid) { - ThreadSP thread_sp(new ThreadMachCore(*this, tid)); - new_thread_list.AddThread(thread_sp); - } - } - } else { - const uint32_t num_threads = old_thread_list.GetSize(false); - for (uint32_t i = 0; i < num_threads; ++i) - new_thread_list.AddThread(old_thread_list.GetThreadAtIndex(i, false)); - } - return new_thread_list.GetSize(false) > 0; -} - -void ProcessMachCore::RefreshStateAfterStop() { - // Let all threads recover from stopping and do any clean up based on the - // previous thread state (if any). - m_thread_list.RefreshStateAfterStop(); - // SetThreadStopInfo (m_last_stop_packet); -} - -Status ProcessMachCore::DoDestroy() { return Status(); } - -//------------------------------------------------------------------ -// Process Queries -//------------------------------------------------------------------ - -bool ProcessMachCore::IsAlive() { return true; } - -bool ProcessMachCore::WarnBeforeDetach() const { return false; } - -//------------------------------------------------------------------ -// Process Memory -//------------------------------------------------------------------ -size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size, - Status &error) { - // Don't allow the caching that lldb_private::Process::ReadMemory does since - // in core files we have it all cached our our core file anyway. - return DoReadMemory(addr, buf, size, error); -} - -size_t ProcessMachCore::DoReadMemory(addr_t addr, void *buf, size_t size, - Status &error) { - ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); - size_t bytes_read = 0; - - if (core_objfile) { - //---------------------------------------------------------------------- - // Segments are not always contiguous in mach-o core files. We have core - // files that have segments like: - // Address Size File off File size - // ---------- ---------- ---------- ---------- - // LC_SEGMENT 0x000f6000 0x00001000 0x1d509ee8 0x00001000 --- --- 0 - // 0x00000000 __TEXT LC_SEGMENT 0x0f600000 0x00100000 0x1d50aee8 0x00100000 - // --- --- 0 0x00000000 __TEXT LC_SEGMENT 0x000f7000 0x00001000 - // 0x1d60aee8 0x00001000 --- --- 0 0x00000000 __TEXT - // - // Any if the user executes the following command: - // - // (lldb) mem read 0xf6ff0 - // - // We would attempt to read 32 bytes from 0xf6ff0 but would only get 16 - // unless we loop through consecutive memory ranges that are contiguous in - // the address space, but not in the file data. - //---------------------------------------------------------------------- - while (bytes_read < size) { - const addr_t curr_addr = addr + bytes_read; - const VMRangeToFileOffset::Entry *core_memory_entry = - m_core_aranges.FindEntryThatContains(curr_addr); - - if (core_memory_entry) { - const addr_t offset = curr_addr - core_memory_entry->GetRangeBase(); - const addr_t bytes_left = core_memory_entry->GetRangeEnd() - curr_addr; - const size_t bytes_to_read = - std::min(size - bytes_read, (size_t)bytes_left); - const size_t curr_bytes_read = core_objfile->CopyData( - core_memory_entry->data.GetRangeBase() + offset, bytes_to_read, - (char *)buf + bytes_read); - if (curr_bytes_read == 0) - break; - bytes_read += curr_bytes_read; - } else { - // Only set the error if we didn't read any bytes - if (bytes_read == 0) - error.SetErrorStringWithFormat( - "core file does not contain 0x%" PRIx64, curr_addr); - break; - } - } - } - - return bytes_read; -} - -Status ProcessMachCore::GetMemoryRegionInfo(addr_t load_addr, - MemoryRegionInfo ®ion_info) { - region_info.Clear(); - const VMRangeToPermissions::Entry *permission_entry = - m_core_range_infos.FindEntryThatContainsOrFollows(load_addr); - if (permission_entry) { - if (permission_entry->Contains(load_addr)) { - region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase()); - region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd()); - const Flags permissions(permission_entry->data); - region_info.SetReadable(permissions.Test(ePermissionsReadable) - ? MemoryRegionInfo::eYes - : MemoryRegionInfo::eNo); - region_info.SetWritable(permissions.Test(ePermissionsWritable) - ? MemoryRegionInfo::eYes - : MemoryRegionInfo::eNo); - region_info.SetExecutable(permissions.Test(ePermissionsExecutable) - ? MemoryRegionInfo::eYes - : MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eYes); - } else if (load_addr < permission_entry->GetRangeBase()) { - region_info.GetRange().SetRangeBase(load_addr); - region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase()); - region_info.SetReadable(MemoryRegionInfo::eNo); - region_info.SetWritable(MemoryRegionInfo::eNo); - region_info.SetExecutable(MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - } - return Status(); - } - - region_info.GetRange().SetRangeBase(load_addr); - region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); - region_info.SetReadable(MemoryRegionInfo::eNo); - region_info.SetWritable(MemoryRegionInfo::eNo); - region_info.SetExecutable(MemoryRegionInfo::eNo); - region_info.SetMapped(MemoryRegionInfo::eNo); - return Status(); -} - -void ProcessMachCore::Clear() { m_thread_list.Clear(); } - -void ProcessMachCore::Initialize() { - static llvm::once_flag g_once_flag; - - llvm::call_once(g_once_flag, []() { - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), CreateInstance); - }); -} - -addr_t ProcessMachCore::GetImageInfoAddress() { - // If we found both a user-process dyld and a kernel binary, we need to - // decide which to prefer. - if (GetCorefilePreference() == eKernelCorefile) { - if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - return m_mach_kernel_addr; - } - return m_dyld_addr; - } else { - if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - return m_dyld_addr; - } - return m_mach_kernel_addr; - } -} - -lldb_private::ObjectFile *ProcessMachCore::GetCoreObjectFile() { - return m_core_module_sp->GetObjectFile(); -} diff --git a/source/Plugins/Process/mach-core/ProcessMachCore.h b/source/Plugins/Process/mach-core/ProcessMachCore.h deleted file mode 100644 index 0c6fc693a50c5..0000000000000 --- a/source/Plugins/Process/mach-core/ProcessMachCore.h +++ /dev/null @@ -1,149 +0,0 @@ -//===-- ProcessMachCore.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ProcessMachCore_h_ -#define liblldb_ProcessMachCore_h_ - -#include <list> -#include <vector> - -#include "lldb/Target/Process.h" -#include "lldb/Utility/ConstString.h" -#include "lldb/Utility/Status.h" - -class ThreadKDP; - -class ProcessMachCore : public lldb_private::Process { -public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - ProcessMachCore(lldb::TargetSP target_sp, lldb::ListenerSP listener, - const lldb_private::FileSpec &core_file); - - ~ProcessMachCore() override; - - static lldb::ProcessSP - CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, - const lldb_private::FileSpec *crash_file_path); - - static void Initialize(); - - static void Terminate(); - - static lldb_private::ConstString GetPluginNameStatic(); - - static const char *GetPluginDescriptionStatic(); - - //------------------------------------------------------------------ - // Check if a given Process - //------------------------------------------------------------------ - bool CanDebug(lldb::TargetSP target_sp, - bool plugin_specified_by_name) override; - - //------------------------------------------------------------------ - // Creating a new process, or attaching to an existing one - //------------------------------------------------------------------ - lldb_private::Status DoLoadCore() override; - - lldb_private::DynamicLoader *GetDynamicLoader() override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; - - //------------------------------------------------------------------ - // Process Control - //------------------------------------------------------------------ - lldb_private::Status DoDestroy() override; - - void RefreshStateAfterStop() override; - - //------------------------------------------------------------------ - // Process Queries - //------------------------------------------------------------------ - bool IsAlive() override; - - bool WarnBeforeDetach() const override; - - //------------------------------------------------------------------ - // Process Memory - //------------------------------------------------------------------ - size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, - lldb_private::Status &error) override; - - size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, - lldb_private::Status &error) override; - - lldb_private::Status - GetMemoryRegionInfo(lldb::addr_t load_addr, - lldb_private::MemoryRegionInfo ®ion_info) override; - - lldb::addr_t GetImageInfoAddress() override; - -protected: - friend class ThreadMachCore; - - void Clear(); - - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; - - lldb_private::ObjectFile *GetCoreObjectFile(); - -private: - bool GetDynamicLoaderAddress(lldb::addr_t addr); - - typedef enum CorefilePreference { - eUserProcessCorefile, - eKernelCorefile - } CorefilePreferences; - - //------------------------------------------------------------------ - /// If a core file can be interpreted multiple ways, this establishes - /// which style wins. - /// - /// If a core file contains both a kernel binary and a user-process - /// dynamic loader, lldb needs to pick one over the other. This could - /// be a kernel corefile that happens to have a copy of dyld in its - /// memory. Or it could be a user process coredump of lldb while doing - /// kernel debugging - so a copy of the kernel is in its heap. This - /// should become a setting so it can be over-ridden when necessary. - //------------------------------------------------------------------ - CorefilePreference GetCorefilePreference() { - // For now, if both user process and kernel binaries a present, - // assume this is a kernel coredump which has a copy of a user - // process dyld in one of its pages. - return eKernelCorefile; - } - - //------------------------------------------------------------------ - // For ProcessMachCore only - //------------------------------------------------------------------ - typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange; - typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange> - VMRangeToFileOffset; - typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t> - VMRangeToPermissions; - - VMRangeToFileOffset m_core_aranges; - VMRangeToPermissions m_core_range_infos; - lldb::ModuleSP m_core_module_sp; - lldb_private::FileSpec m_core_file; - lldb::addr_t m_dyld_addr; - lldb::addr_t m_mach_kernel_addr; - lldb_private::ConstString m_dyld_plugin_name; - - DISALLOW_COPY_AND_ASSIGN(ProcessMachCore); -}; - -#endif // liblldb_ProcessMachCore_h_ diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.cpp b/source/Plugins/Process/mach-core/ThreadMachCore.cpp deleted file mode 100644 index 16edd28f1a132..0000000000000 --- a/source/Plugins/Process/mach-core/ThreadMachCore.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//===-- ThreadMachCore.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ThreadMachCore.h" - -#include "lldb/Breakpoint/Watchpoint.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StopInfo.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Unwind.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/State.h" -#include "lldb/Utility/StreamString.h" - -#include "ProcessMachCore.h" -//#include "RegisterContextKDP_arm.h" -//#include "RegisterContextKDP_i386.h" -//#include "RegisterContextKDP_x86_64.h" - -using namespace lldb; -using namespace lldb_private; - -//---------------------------------------------------------------------- -// Thread Registers -//---------------------------------------------------------------------- - -ThreadMachCore::ThreadMachCore(Process &process, lldb::tid_t tid) - : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(), - m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS), m_thread_reg_ctx_sp() {} - -ThreadMachCore::~ThreadMachCore() { DestroyThread(); } - -const char *ThreadMachCore::GetName() { - if (m_thread_name.empty()) - return nullptr; - return m_thread_name.c_str(); -} - -void ThreadMachCore::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. - const bool force = false; - GetRegisterContext()->InvalidateIfNeeded(force); -} - -bool ThreadMachCore::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; } - -lldb::RegisterContextSP ThreadMachCore::GetRegisterContext() { - if (!m_reg_context_sp) - m_reg_context_sp = CreateRegisterContextForFrame(nullptr); - return m_reg_context_sp; -} - -lldb::RegisterContextSP -ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; - uint32_t concrete_frame_idx = 0; - - if (frame) - concrete_frame_idx = frame->GetConcreteFrameIndex(); - - if (concrete_frame_idx == 0) { - if (!m_thread_reg_ctx_sp) { - ProcessSP process_sp(GetProcess()); - - ObjectFile *core_objfile = - static_cast<ProcessMachCore *>(process_sp.get())->GetCoreObjectFile(); - if (core_objfile) - m_thread_reg_ctx_sp = - core_objfile->GetThreadContextAtIndex(GetID(), *this); - } - reg_ctx_sp = m_thread_reg_ctx_sp; - } else { - Unwind *unwinder = GetUnwinder(); - if (unwinder != nullptr) - reg_ctx_sp = unwinder->CreateRegisterContextForFrame(frame); - } - return reg_ctx_sp; -} - -bool ThreadMachCore::CalculateStopInfo() { - ProcessSP process_sp(GetProcess()); - if (process_sp) { - SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP)); - return true; - } - return false; -} diff --git a/source/Plugins/Process/mach-core/ThreadMachCore.h b/source/Plugins/Process/mach-core/ThreadMachCore.h deleted file mode 100644 index 696ba7294e4aa..0000000000000 --- a/source/Plugins/Process/mach-core/ThreadMachCore.h +++ /dev/null @@ -1,70 +0,0 @@ -//===-- ThreadMachCore.h ----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ThreadMachCore_h_ -#define liblldb_ThreadMachCore_h_ - -#include <string> - -#include "lldb/Target/Thread.h" - -class ProcessMachCore; - -class ThreadMachCore : public lldb_private::Thread { -public: - ThreadMachCore(lldb_private::Process &process, lldb::tid_t tid); - - ~ThreadMachCore() override; - - void RefreshStateAfterStop() override; - - const char *GetName() override; - - lldb::RegisterContextSP GetRegisterContext() override; - - lldb::RegisterContextSP - CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; - - static bool ThreadIDIsValid(lldb::tid_t thread); - - bool ShouldStop(bool &step_more); - - const char *GetBasicInfoAsString(); - - void SetName(const char *name) override { - if (name && name[0]) - m_thread_name.assign(name); - else - m_thread_name.clear(); - } - - lldb::addr_t GetThreadDispatchQAddr() { return m_thread_dispatch_qaddr; } - - void SetThreadDispatchQAddr(lldb::addr_t thread_dispatch_qaddr) { - m_thread_dispatch_qaddr = thread_dispatch_qaddr; - } - -protected: - friend class ProcessMachCore; - - //------------------------------------------------------------------ - // Member variables. - //------------------------------------------------------------------ - std::string m_thread_name; - std::string m_dispatch_queue_name; - lldb::addr_t m_thread_dispatch_qaddr; - lldb::RegisterContextSP m_thread_reg_ctx_sp; - - //------------------------------------------------------------------ - // Protected member functions. - //------------------------------------------------------------------ - bool CalculateStopInfo() override; -}; - -#endif // liblldb_ThreadMachCore_h_ diff --git a/source/Plugins/Process/minidump/CMakeLists.txt b/source/Plugins/Process/minidump/CMakeLists.txt deleted file mode 100644 index 4126a7ea991c2..0000000000000 --- a/source/Plugins/Process/minidump/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -add_lldb_library(lldbPluginProcessMinidump PLUGIN - MinidumpTypes.cpp - MinidumpParser.cpp - RegisterContextMinidump_ARM.cpp - RegisterContextMinidump_ARM64.cpp - RegisterContextMinidump_x86_32.cpp - RegisterContextMinidump_x86_64.cpp - ProcessMinidump.cpp - ThreadMinidump.cpp - - LINK_LIBS - lldbCore - lldbTarget - lldbUtility - lldbPluginProcessUtility - lldbPluginProcessElfCore - LINK_COMPONENTS - Support - ) |