summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux/NativeThreadLinux.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Linux/NativeThreadLinux.cpp')
-rw-r--r--source/Plugins/Process/Linux/NativeThreadLinux.cpp451
1 files changed, 0 insertions, 451 deletions
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);
-}