diff options
Diffstat (limited to 'source/Plugins/Process/Linux')
24 files changed, 0 insertions, 10598 deletions
diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt deleted file mode 100644 index b4b4c401a271..000000000000 --- 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 8c6c95380e81..000000000000 --- 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 69f2b528d330..000000000000 --- 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 79f635c88985..000000000000 --- 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 2cea497b53bc..000000000000 --- 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 09d3a12942f0..000000000000 --- 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 d0b068550a9e..000000000000 --- 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 9a392edbe9ef..000000000000 --- 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 c859d4249d05..000000000000 --- 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 d641056a0440..000000000000 --- 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 c4e984a545bc..000000000000 --- 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 da51fda1c80b..000000000000 --- 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 2c4471962ad0..000000000000 --- 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 1bc916b69bcd..000000000000 --- 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 57b1a0481512..000000000000 --- 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 50bf29b094df..000000000000 --- 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 9dcf82f50a45..000000000000 --- 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 b64689c9d17b..000000000000 --- 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 a7c4e982012d..000000000000 --- 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 505c526ab70d..000000000000 --- 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 6fd918c2bb58..000000000000 --- 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 1d9c9dbe273f..000000000000 --- 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 c57a2daf2275..000000000000 --- 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 afeda7310349..000000000000 --- 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_ |