summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Linux')
-rw-r--r--source/Plugins/Process/Linux/CMakeLists.txt24
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.cpp2097
-rw-r--r--source/Plugins/Process/Linux/NativeProcessLinux.h261
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp196
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux.h85
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp975
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h169
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp985
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h169
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp1053
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h140
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp804
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h149
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp638
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h115
-rwxr-xr-xsource/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp1213
-rw-r--r--source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h149
-rw-r--r--source/Plugins/Process/Linux/NativeThreadLinux.cpp451
-rw-r--r--source/Plugins/Process/Linux/NativeThreadLinux.h119
-rw-r--r--source/Plugins/Process/Linux/ProcessorTrace.cpp395
-rw-r--r--source/Plugins/Process/Linux/ProcessorTrace.h141
-rw-r--r--source/Plugins/Process/Linux/Procfs.h31
-rw-r--r--source/Plugins/Process/Linux/SingleStepCheck.cpp182
-rw-r--r--source/Plugins/Process/Linux/SingleStepCheck.h57
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 &reg_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 &reg_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 &reg_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 &regsiter_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 &reg_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 &reg_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 *>(&regset), 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 *>(&regset), 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 &reg_value);
-
- virtual Status WriteRegisterRaw(uint32_t reg_index,
- const RegisterValue &reg_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 &reg_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 &reg_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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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 &reg_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 &reg_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, &regset,
- &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, &regset,
- &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 = &regs;
- ioVec.iov_len = sizeof regs;
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_GETREGSET, m_thread.GetID(), &regset, &ioVec, sizeof regs);
- if (error.Success()) {
- value.SetBytes((void *)(((unsigned char *)(&regs)) + offset), 16,
- m_thread.GetProcess().GetByteOrder());
- }
- } else {
- elf_gregset_t regs;
- int regset = NT_PRSTATUS;
- struct iovec ioVec;
-
- ioVec.iov_base = &regs;
- ioVec.iov_len = sizeof regs;
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_GETREGSET, m_thread.GetID(), &regset, &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 = &regs;
- ioVec.iov_len = sizeof regs;
- error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
- &ioVec, sizeof regs);
-
- if (error.Success()) {
- ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
- 16);
- error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
- &ioVec, sizeof regs);
- }
- } else {
- elf_gregset_t regs;
- int regset = NT_PRSTATUS;
- struct iovec ioVec;
-
- ioVec.iov_base = &regs;
- ioVec.iov_len = sizeof regs;
- error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
- &ioVec, sizeof regs);
- if (error.Success()) {
- ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
- 8);
- error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
- &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(),
- &regset, &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(),
- &regset, &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(),
- &regset, &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(),
- &regset, &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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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 &reg_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 &reg_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(&regs_copy, index);
- hi = GetRegMask(&regs_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(&regs_copy, index, (addr & ~mask) | irw);
- SetWatchHi(&regs_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 *>(&regset), &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 *>(&regs));
-
- 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 *>(&regs));
- 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 *>(&regs));
-
- // Try if a new watch point fits in this state
- int index = GetVacantWatchIndex(&regs, 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 *>(&regs));
-
- // 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 &reg_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 &reg_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 *>(&regs));
- 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(&regs, 0, sizeof(GPR_linux_mips));
-
- Status error = NativeProcessLinux::PtraceWrapper(
- PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
- if (error.Success()) {
- const lldb_private::ArchSpec &arch =
- m_thread.GetProcess().GetArchitecture();
- void *target_address = ((uint8_t *)&regs) + 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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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 &reg_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 &reg_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(),
- &regset, 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(),
- &regset, 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(),
- &regset, 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(),
- &regset, 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(),
- &regset, &m_vmx_ppc64le,
- sizeof(m_vmx_ppc64le));
-}
-
-Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
- int regset = NT_PPC_VMX;
- return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
- &regset, &m_vmx_ppc64le,
- sizeof(m_vmx_ppc64le));
-}
-
-Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
- int regset = NT_PPC_VSX;
- return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
- &regset, &m_vsx_ppc64le,
- sizeof(m_vsx_ppc64le));
-}
-
-Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
- int regset = NT_PPC_VSX;
- return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
- &regset, &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, &reg_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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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 &reg_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(&regs, sizeof(regs));
- if (error.Fail())
- return error;
-
- uint8_t *src = (uint8_t *)&regs + 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 &reg_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(&regs, sizeof(regs));
- if (error.Fail())
- return error;
-
- uint8_t *dst = (uint8_t *)&regs + 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(&regs, 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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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 &reg_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 &reg_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 &reg_value) override;
-
- Status WriteRegister(const RegisterInfo *reg_info,
- const RegisterValue &reg_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_