| //===-- FreeBSDThread.cpp -------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <errno.h> |
| #include <pthread.h> |
| #include <pthread_np.h> |
| #include <stdlib.h> |
| #include <sys/sysctl.h> |
| #include <sys/types.h> |
| #include <sys/user.h> |
| |
| #include "FreeBSDThread.h" |
| #include "POSIXStopInfo.h" |
| #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" |
| #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" |
| #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" |
| #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" |
| #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" |
| #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" |
| #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" |
| #include "ProcessFreeBSD.h" |
| #include "ProcessMonitor.h" |
| #include "RegisterContextPOSIXProcessMonitor_arm.h" |
| #include "RegisterContextPOSIXProcessMonitor_arm64.h" |
| #include "RegisterContextPOSIXProcessMonitor_mips64.h" |
| #include "RegisterContextPOSIXProcessMonitor_powerpc.h" |
| #include "RegisterContextPOSIXProcessMonitor_x86.h" |
| #include "lldb/Breakpoint/BreakpointLocation.h" |
| #include "lldb/Breakpoint/Watchpoint.h" |
| #include "lldb/Core/Debugger.h" |
| #include "lldb/Host/Host.h" |
| #include "lldb/Host/HostInfo.h" |
| #include "lldb/Host/HostNativeThread.h" |
| #include "lldb/Target/Process.h" |
| #include "lldb/Target/StopInfo.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/ThreadSpec.h" |
| #include "lldb/Target/UnixSignals.h" |
| #include "lldb/Target/Unwind.h" |
| #include "lldb/Utility/State.h" |
| #include "llvm/ADT/SmallString.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid) |
| : Thread(process, tid), m_frame_up(), m_breakpoint(), |
| m_thread_name_valid(false), m_thread_name(), m_posix_thread(nullptr) { |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| LLDB_LOGV(log, "tid = {0}", tid); |
| |
| // Set the current watchpoints for this thread. |
| Target &target = GetProcess()->GetTarget(); |
| const WatchpointList &wp_list = target.GetWatchpointList(); |
| size_t wp_size = wp_list.GetSize(); |
| |
| for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) { |
| lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); |
| if (wp.get() && wp->IsEnabled()) { |
| // This watchpoint as been enabled; obviously this "new" thread has been |
| // created since that watchpoint was enabled. Since the |
| // POSIXBreakpointProtocol has yet to be initialized, its |
| // m_watchpoints_initialized member will be FALSE. Attempting to read |
| // the debug status register to determine if a watchpoint has been hit |
| // would result in the zeroing of that register. Since the active debug |
| // registers would have been cloned when this thread was created, simply |
| // force the m_watchpoints_initized member to TRUE and avoid resetting |
| // dr6 and dr7. |
| GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); |
| } |
| } |
| } |
| |
| FreeBSDThread::~FreeBSDThread() { DestroyThread(); } |
| |
| ProcessMonitor &FreeBSDThread::GetMonitor() { |
| ProcessSP base = GetProcess(); |
| ProcessFreeBSD &process = static_cast<ProcessFreeBSD &>(*base); |
| return process.GetMonitor(); |
| } |
| |
| void FreeBSDThread::RefreshStateAfterStop() { |
| // Invalidate all registers in our register context. We don't set "force" to |
| // true because the stop reply packet might have had some register values |
| // that were expedited and these will already be copied into the register |
| // context by the time this function gets called. The KDPRegisterContext |
| // class has been made smart enough to detect when it needs to invalidate |
| // which registers are valid by putting hooks in the register read and |
| // register supply functions where they check the process stop ID and do the |
| // right thing. if (StateIsStoppedState(GetState()) |
| { |
| const bool force = false; |
| GetRegisterContext()->InvalidateIfNeeded(force); |
| } |
| } |
| |
| const char *FreeBSDThread::GetInfo() { return nullptr; } |
| |
| void FreeBSDThread::SetName(const char *name) { |
| m_thread_name_valid = (name && name[0]); |
| if (m_thread_name_valid) |
| m_thread_name.assign(name); |
| else |
| m_thread_name.clear(); |
| } |
| |
| const char *FreeBSDThread::GetName() { |
| if (!m_thread_name_valid) { |
| m_thread_name.clear(); |
| int pid = GetProcess()->GetID(); |
| |
| struct kinfo_proc *kp = nullptr, *nkp; |
| size_t len = 0; |
| int error; |
| int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, |
| pid}; |
| |
| while (1) { |
| error = sysctl(ctl, 4, kp, &len, nullptr, 0); |
| if (kp == nullptr || (error != 0 && errno == ENOMEM)) { |
| // Add extra space in case threads are added before next call. |
| len += sizeof(*kp) + len / 10; |
| nkp = (struct kinfo_proc *)realloc(kp, len); |
| if (nkp == nullptr) { |
| free(kp); |
| return nullptr; |
| } |
| kp = nkp; |
| continue; |
| } |
| if (error != 0) |
| len = 0; |
| break; |
| } |
| |
| for (size_t i = 0; i < len / sizeof(*kp); i++) { |
| if (kp[i].ki_tid == (lwpid_t)GetID()) { |
| m_thread_name.append(kp[i].ki_tdname, |
| kp[i].ki_tdname + strlen(kp[i].ki_tdname)); |
| break; |
| } |
| } |
| free(kp); |
| m_thread_name_valid = true; |
| } |
| |
| if (m_thread_name.empty()) |
| return nullptr; |
| return m_thread_name.c_str(); |
| } |
| |
| lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() { |
| if (!m_reg_context_sp) { |
| m_posix_thread = nullptr; |
| |
| RegisterInfoInterface *reg_interface = nullptr; |
| const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); |
| |
| assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD); |
| switch (target_arch.GetMachine()) { |
| case llvm::Triple::aarch64: |
| break; |
| case llvm::Triple::arm: |
| reg_interface = new RegisterInfoPOSIX_arm(target_arch); |
| break; |
| case llvm::Triple::ppc: |
| #ifndef __powerpc64__ |
| reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch); |
| break; |
| #endif |
| case llvm::Triple::ppc64: |
| reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch); |
| break; |
| case llvm::Triple::mips64: |
| reg_interface = new RegisterContextFreeBSD_mips64(target_arch); |
| break; |
| case llvm::Triple::x86: |
| reg_interface = new RegisterContextFreeBSD_i386(target_arch); |
| break; |
| case llvm::Triple::x86_64: |
| reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); |
| break; |
| default: |
| llvm_unreachable("CPU not supported"); |
| } |
| |
| switch (target_arch.GetMachine()) { |
| case llvm::Triple::aarch64: { |
| RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = |
| new RegisterContextPOSIXProcessMonitor_arm64( |
| *this, std::make_unique<RegisterInfoPOSIX_arm64>(target_arch)); |
| m_posix_thread = reg_ctx; |
| m_reg_context_sp.reset(reg_ctx); |
| break; |
| } |
| case llvm::Triple::arm: { |
| RegisterContextPOSIXProcessMonitor_arm *reg_ctx = |
| new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface); |
| m_posix_thread = reg_ctx; |
| m_reg_context_sp.reset(reg_ctx); |
| break; |
| } |
| case llvm::Triple::mips64: { |
| RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = |
| new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, |
| reg_interface); |
| m_posix_thread = reg_ctx; |
| m_reg_context_sp.reset(reg_ctx); |
| break; |
| } |
| case llvm::Triple::ppc: |
| case llvm::Triple::ppc64: { |
| RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = |
| new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, |
| reg_interface); |
| m_posix_thread = reg_ctx; |
| m_reg_context_sp.reset(reg_ctx); |
| break; |
| } |
| case llvm::Triple::x86: |
| case llvm::Triple::x86_64: { |
| RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = |
| new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, |
| reg_interface); |
| m_posix_thread = reg_ctx; |
| m_reg_context_sp.reset(reg_ctx); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| return m_reg_context_sp; |
| } |
| |
| lldb::RegisterContextSP |
| FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) { |
| lldb::RegisterContextSP reg_ctx_sp; |
| uint32_t concrete_frame_idx = 0; |
| |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| LLDB_LOGV(log, "called"); |
| |
| if (frame) |
| concrete_frame_idx = frame->GetConcreteFrameIndex(); |
| |
| if (concrete_frame_idx == 0) |
| reg_ctx_sp = GetRegisterContext(); |
| else { |
| reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); |
| } |
| |
| return reg_ctx_sp; |
| } |
| |
| lldb::addr_t FreeBSDThread::GetThreadPointer() { |
| ProcessMonitor &monitor = GetMonitor(); |
| addr_t addr; |
| if (monitor.ReadThreadPointer(GetID(), addr)) |
| return addr; |
| else |
| return LLDB_INVALID_ADDRESS; |
| } |
| |
| bool FreeBSDThread::CalculateStopInfo() { |
| SetStopInfo(m_stop_info_sp); |
| return true; |
| } |
| |
| void FreeBSDThread::DidStop() { |
| // Don't set the thread state to stopped unless we really stopped. |
| } |
| |
| void FreeBSDThread::WillResume(lldb::StateType resume_state) { |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| LLDB_LOGF(log, "tid %lu resume_state = %s", GetID(), |
| lldb_private::StateAsCString(resume_state)); |
| ProcessSP process_sp(GetProcess()); |
| ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get()); |
| int signo = GetResumeSignal(); |
| bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo); |
| |
| switch (resume_state) { |
| case eStateSuspended: |
| case eStateStopped: |
| process->m_suspend_tids.push_back(GetID()); |
| break; |
| case eStateRunning: |
| process->m_run_tids.push_back(GetID()); |
| if (signo_valid) |
| process->m_resume_signo = signo; |
| break; |
| case eStateStepping: |
| process->m_step_tids.push_back(GetID()); |
| if (signo_valid) |
| process->m_resume_signo = signo; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| bool FreeBSDThread::Resume() { |
| lldb::StateType resume_state = GetResumeState(); |
| ProcessMonitor &monitor = GetMonitor(); |
| bool status; |
| |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| LLDB_LOGF(log, "FreeBSDThread::%s (), resume_state = %s", __FUNCTION__, |
| StateAsCString(resume_state)); |
| |
| switch (resume_state) { |
| default: |
| assert(false && "Unexpected state for resume!"); |
| status = false; |
| break; |
| |
| case lldb::eStateRunning: |
| SetState(resume_state); |
| status = monitor.Resume(GetID(), GetResumeSignal()); |
| break; |
| |
| case lldb::eStateStepping: |
| SetState(resume_state); |
| status = monitor.SingleStep(GetID(), GetResumeSignal()); |
| break; |
| case lldb::eStateStopped: |
| case lldb::eStateSuspended: |
| status = true; |
| break; |
| } |
| |
| return status; |
| } |
| |
| void FreeBSDThread::Notify(const ProcessMessage &message) { |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| LLDB_LOGF(log, "FreeBSDThread::%s () message kind = '%s' for tid %" PRIu64, |
| __FUNCTION__, message.PrintKind(), GetID()); |
| |
| switch (message.GetKind()) { |
| default: |
| assert(false && "Unexpected message kind!"); |
| break; |
| |
| case ProcessMessage::eExitMessage: |
| // Nothing to be done. |
| break; |
| |
| case ProcessMessage::eLimboMessage: |
| LimboNotify(message); |
| break; |
| |
| case ProcessMessage::eCrashMessage: |
| case ProcessMessage::eSignalMessage: |
| SignalNotify(message); |
| break; |
| |
| case ProcessMessage::eSignalDeliveredMessage: |
| SignalDeliveredNotify(message); |
| break; |
| |
| case ProcessMessage::eTraceMessage: |
| TraceNotify(message); |
| break; |
| |
| case ProcessMessage::eBreakpointMessage: |
| BreakNotify(message); |
| break; |
| |
| case ProcessMessage::eWatchpointMessage: |
| WatchNotify(message); |
| break; |
| |
| case ProcessMessage::eExecMessage: |
| ExecNotify(message); |
| break; |
| } |
| } |
| |
| bool FreeBSDThread::EnableHardwareWatchpoint(Watchpoint *wp) { |
| bool wp_set = false; |
| if (wp) { |
| addr_t wp_addr = wp->GetLoadAddress(); |
| size_t wp_size = wp->GetByteSize(); |
| bool wp_read = wp->WatchpointRead(); |
| bool wp_write = wp->WatchpointWrite(); |
| uint32_t wp_hw_index = wp->GetHardwareIndex(); |
| POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); |
| if (reg_ctx) |
| wp_set = reg_ctx->SetHardwareWatchpointWithIndex( |
| wp_addr, wp_size, wp_read, wp_write, wp_hw_index); |
| } |
| return wp_set; |
| } |
| |
| bool FreeBSDThread::DisableHardwareWatchpoint(Watchpoint *wp) { |
| bool result = false; |
| if (wp) { |
| lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); |
| if (reg_ctx_sp.get()) |
| result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex()); |
| } |
| return result; |
| } |
| |
| uint32_t FreeBSDThread::NumSupportedHardwareWatchpoints() { |
| lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext(); |
| if (reg_ctx_sp.get()) |
| return reg_ctx_sp->NumSupportedHardwareWatchpoints(); |
| return 0; |
| } |
| |
| uint32_t FreeBSDThread::FindVacantWatchpointIndex() { |
| uint32_t hw_index = LLDB_INVALID_INDEX32; |
| uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); |
| uint32_t wp_idx; |
| POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); |
| if (reg_ctx) { |
| for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { |
| if (reg_ctx->IsWatchpointVacant(wp_idx)) { |
| hw_index = wp_idx; |
| break; |
| } |
| } |
| } |
| return hw_index; |
| } |
| |
| void FreeBSDThread::BreakNotify(const ProcessMessage &message) { |
| bool status; |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| |
| assert(GetRegisterContext()); |
| status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); |
| assert(status && "Breakpoint update failed!"); |
| |
| // With our register state restored, resolve the breakpoint object |
| // corresponding to our current PC. |
| assert(GetRegisterContext()); |
| lldb::addr_t pc = GetRegisterContext()->GetPC(); |
| LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); |
| lldb::BreakpointSiteSP bp_site( |
| GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); |
| |
| // If the breakpoint is for this thread, then we'll report the hit, but if it |
| // is for another thread, we create a stop reason with should_stop=false. If |
| // there is no breakpoint location, then report an invalid stop reason. We |
| // don't need to worry about stepping over the breakpoint here, that will be |
| // taken care of when the thread resumes and notices that there's a |
| // breakpoint under the pc. |
| if (bp_site) { |
| lldb::break_id_t bp_id = bp_site->GetID(); |
| // If we have an operating system plug-in, we might have set a thread |
| // specific breakpoint using the operating system thread ID, so we can't |
| // make any assumptions about the thread ID so we must always report the |
| // breakpoint regardless of the thread. |
| if (bp_site->ValidForThisThread(this) || |
| GetProcess()->GetOperatingSystem() != nullptr) |
| SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); |
| else { |
| const bool should_stop = false; |
| SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, |
| should_stop)); |
| } |
| } else |
| SetStopInfo(StopInfoSP()); |
| } |
| |
| void FreeBSDThread::WatchNotify(const ProcessMessage &message) { |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| |
| lldb::addr_t halt_addr = message.GetHWAddress(); |
| LLDB_LOGF(log, |
| "FreeBSDThread::%s () Hardware Watchpoint Address = 0x%8.8" PRIx64, |
| __FUNCTION__, halt_addr); |
| |
| POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); |
| if (reg_ctx) { |
| uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); |
| uint32_t wp_idx; |
| for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { |
| if (reg_ctx->IsWatchpointHit(wp_idx)) { |
| // Clear the watchpoint hit here |
| reg_ctx->ClearWatchpointHits(); |
| break; |
| } |
| } |
| |
| if (wp_idx == num_hw_wps) |
| return; |
| |
| Target &target = GetProcess()->GetTarget(); |
| lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx); |
| const WatchpointList &wp_list = target.GetWatchpointList(); |
| lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr); |
| |
| assert(wp_sp.get() && "No watchpoint found"); |
| SetStopInfo( |
| StopInfo::CreateStopReasonWithWatchpointID(*this, wp_sp->GetID())); |
| } |
| } |
| |
| void FreeBSDThread::TraceNotify(const ProcessMessage &message) { |
| Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); |
| |
| // Try to resolve the breakpoint object corresponding to the current PC. |
| assert(GetRegisterContext()); |
| lldb::addr_t pc = GetRegisterContext()->GetPC(); |
| LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc); |
| lldb::BreakpointSiteSP bp_site( |
| GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); |
| |
| // If the current pc is a breakpoint site then set the StopInfo to |
| // Breakpoint. Otherwise, set the StopInfo to Watchpoint or Trace. If we have |
| // an operating system plug-in, we might have set a thread specific |
| // breakpoint using the operating system thread ID, so we can't make any |
| // assumptions about the thread ID so we must always report the breakpoint |
| // regardless of the thread. |
| if (bp_site && (bp_site->ValidForThisThread(this) || |
| GetProcess()->GetOperatingSystem() != nullptr)) |
| SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( |
| *this, bp_site->GetID())); |
| else { |
| POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); |
| if (reg_ctx) { |
| uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); |
| uint32_t wp_idx; |
| for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) { |
| if (reg_ctx->IsWatchpointHit(wp_idx)) { |
| WatchNotify(message); |
| return; |
| } |
| } |
| } |
| SetStopInfo(StopInfo::CreateStopReasonToTrace(*this)); |
| } |
| } |
| |
| void FreeBSDThread::LimboNotify(const ProcessMessage &message) { |
| SetStopInfo(lldb::StopInfoSP(new POSIXLimboStopInfo(*this))); |
| } |
| |
| void FreeBSDThread::SignalNotify(const ProcessMessage &message) { |
| int signo = message.GetSignal(); |
| if (message.GetKind() == ProcessMessage::eCrashMessage) { |
| std::string stop_description = GetCrashReasonString( |
| message.GetCrashReason(), message.GetFaultAddress()); |
| SetStopInfo(StopInfo::CreateStopReasonWithSignal( |
| *this, signo, stop_description.c_str())); |
| } else { |
| SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); |
| } |
| } |
| |
| void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) { |
| int signo = message.GetSignal(); |
| SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo)); |
| } |
| |
| unsigned FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) { |
| unsigned reg = LLDB_INVALID_REGNUM; |
| ArchSpec arch = HostInfo::GetArchitecture(); |
| |
| switch (arch.GetMachine()) { |
| default: |
| llvm_unreachable("CPU type not supported!"); |
| break; |
| |
| case llvm::Triple::aarch64: |
| case llvm::Triple::arm: |
| case llvm::Triple::mips64: |
| case llvm::Triple::ppc: |
| case llvm::Triple::ppc64: |
| case llvm::Triple::x86: |
| case llvm::Triple::x86_64: { |
| POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol(); |
| reg = reg_ctx->GetRegisterIndexFromOffset(offset); |
| } break; |
| } |
| return reg; |
| } |
| |
| void FreeBSDThread::ExecNotify(const ProcessMessage &message) { |
| SetStopInfo(StopInfo::CreateStopReasonWithExec(*this)); |
| } |
| |
| const char *FreeBSDThread::GetRegisterName(unsigned reg) { |
| const char *name = nullptr; |
| ArchSpec arch = HostInfo::GetArchitecture(); |
| |
| switch (arch.GetMachine()) { |
| default: |
| assert(false && "CPU type not supported!"); |
| break; |
| |
| case llvm::Triple::aarch64: |
| case llvm::Triple::arm: |
| case llvm::Triple::mips64: |
| case llvm::Triple::ppc: |
| case llvm::Triple::ppc64: |
| case llvm::Triple::x86: |
| case llvm::Triple::x86_64: |
| name = GetRegisterContext()->GetRegisterName(reg); |
| break; |
| } |
| return name; |
| } |
| |
| const char *FreeBSDThread::GetRegisterNameFromOffset(unsigned offset) { |
| return GetRegisterName(GetRegisterIndexFromOffset(offset)); |
| } |