From ef5d0b5e97ec8e6fa395d377b09aa7755e345b4f Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 18 Dec 2017 20:12:36 +0000 Subject: Vendor import of lldb trunk r321017: https://llvm.org/svn/llvm-project/lldb/trunk@321017 --- source/Plugins/Process/Linux/CMakeLists.txt | 3 +- .../Plugins/Process/Linux/NativeProcessLinux.cpp | 282 +++----- source/Plugins/Process/Linux/NativeProcessLinux.h | 9 +- .../Process/Linux/NativeRegisterContextLinux.cpp | 16 +- .../Process/Linux/NativeRegisterContextLinux.h | 19 +- .../Linux/NativeRegisterContextLinux_arm.cpp | 22 +- .../Process/Linux/NativeRegisterContextLinux_arm.h | 3 +- .../Linux/NativeRegisterContextLinux_arm64.cpp | 34 +- .../Linux/NativeRegisterContextLinux_arm64.h | 3 +- .../Linux/NativeRegisterContextLinux_mips64.cpp | 26 +- .../Linux/NativeRegisterContextLinux_mips64.h | 6 +- .../Linux/NativeRegisterContextLinux_ppc64le.cpp | 801 +++++++++++++++++++++ .../Linux/NativeRegisterContextLinux_ppc64le.h | 149 ++++ .../Linux/NativeRegisterContextLinux_s390x.cpp | 14 +- .../Linux/NativeRegisterContextLinux_s390x.h | 3 +- .../Linux/NativeRegisterContextLinux_x86_64.cpp | 120 +-- .../Linux/NativeRegisterContextLinux_x86_64.h | 8 +- source/Plugins/Process/Linux/NativeThreadLinux.cpp | 42 +- source/Plugins/Process/Linux/NativeThreadLinux.h | 11 +- 19 files changed, 1211 insertions(+), 360 deletions(-) create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h (limited to 'source/Plugins/Process/Linux') diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt index 8330cac160e6..390dbd9ff8bf 100644 --- a/source/Plugins/Process/Linux/CMakeLists.txt +++ b/source/Plugins/Process/Linux/CMakeLists.txt @@ -7,9 +7,10 @@ add_lldb_library(lldbPluginProcessLinux PLUGIN NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp - NativeRegisterContextLinux_x86_64.cpp NativeRegisterContextLinux_mips64.cpp + NativeRegisterContextLinux_ppc64le.cpp NativeRegisterContextLinux_s390x.cpp + NativeRegisterContextLinux_x86_64.cpp NativeThreadLinux.cpp ProcessorTrace.cpp SingleStepCheck.cpp diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 170d3b100064..136af361af29 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -177,7 +177,7 @@ void PtraceDisplayBytes(int &req, void *data, size_t data_size) { break; } case PTRACE_SETREGSET: { - // Extract iov_base from data, which is a pointer to the struct IOVEC + // 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; @@ -305,10 +305,9 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, assert(m_sigchld_handle && status.Success()); for (const auto &tid : tids) { - NativeThreadLinuxSP thread_sp = AddThread(tid); - assert(thread_sp && "AddThread() returned a nullptr thread"); - thread_sp->SetStoppedBySignal(SIGSTOP); - ThreadWasCreated(*thread_sp); + NativeThreadLinux &thread = AddThread(tid); + thread.SetStoppedBySignal(SIGSTOP); + ThreadWasCreated(thread); } // Let our process instance know the thread has stopped. @@ -413,46 +412,20 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, // Handle when the thread exits. if (exited) { - LLDB_LOG(log, "got exit signal({0}) , tid = {1} ({2} main thread)", signal, - pid, is_main_thread ? "is" : "is not"); + 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. - const bool thread_found = StopTrackingThread(pid); + StopTrackingThread(pid); if (is_main_thread) { - // We only set the exit status and notify the delegate if we haven't - // already set the process - // state to an exited state. We normally should have received a SIGTRAP | - // (PTRACE_EVENT_EXIT << 8) - // for the main thread. - const bool already_notified = (GetState() == StateType::eStateExited) || - (GetState() == StateType::eStateCrashed); - if (!already_notified) { - LLDB_LOG( - log, - "tid = {0} handling main thread exit ({1}), expected exit state " - "already set but state was {2} instead, setting exit state now", - pid, - thread_found ? "stopped tracking thread metadata" - : "thread metadata not found", - GetState()); - // The main thread exited. We're done monitoring. Report to delegate. - SetExitStatus(status, true); + // 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); - } else - LLDB_LOG(log, "tid = {0} main thread now exited (%s)", pid, - thread_found ? "stopped tracking thread metadata" - : "thread metadata not found"); - } else { - // Do we want to report to the delegate in this case? I think not. If - // this was an orderly thread exit, we would already have received the - // SIGTRAP | (PTRACE_EVENT_EXIT << 8) signal, and we would have done an - // all-stop then. - LLDB_LOG(log, "tid = {0} handling non-main thread exit (%s)", pid, - thread_found ? "stopped tracking thread metadata" - : "thread metadata not found"); + // Notify delegate that our process has exited. + SetState(StateType::eStateExited, true); } return; } @@ -478,11 +451,11 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, LLDB_LOG(log, "tid {0}, si_code: {1}, si_pid: {2}", pid, info.si_code, info.si_pid); - auto thread_sp = AddThread(pid); + NativeThreadLinux &thread = AddThread(pid); // Resume the newly created thread. - ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(*thread_sp); + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + ThreadWasCreated(thread); return; } @@ -549,12 +522,9 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, void NativeProcessLinux::WaitForNewThread(::pid_t tid) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - NativeThreadLinuxSP new_thread_sp = GetThreadByID(tid); - - if (new_thread_sp) { + 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. + // (see MonitorSignal) before this one. We are done. return; } @@ -587,10 +557,10 @@ void NativeProcessLinux::WaitForNewThread(::pid_t tid) { } LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid); - new_thread_sp = AddThread(tid); + NativeThreadLinux &new_thread = AddThread(tid); - ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(*new_thread_sp); + ResumeThread(new_thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + ThreadWasCreated(new_thread); } void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, @@ -630,7 +600,6 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, } case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)): { - NativeThreadLinuxSP main_thread_sp; LLDB_LOG(log, "received exec event, code = {0}", info.si_code ^ SIGTRAP); // Exec clears any pending notifications. @@ -640,44 +609,26 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, // which only copies the main thread. LLDB_LOG(log, "exec received, stop tracking all but main thread"); - for (auto thread_sp : m_threads) { - const bool is_main_thread = thread_sp && thread_sp->GetID() == GetID(); - if (is_main_thread) { - main_thread_sp = std::static_pointer_cast(thread_sp); - LLDB_LOG(log, "found main thread with tid {0}, keeping", - main_thread_sp->GetID()); - } else { - LLDB_LOG(log, "discarding non-main-thread tid {0} due to exec", - thread_sp->GetID()); - } + 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(m_threads[0].get()); - m_threads.clear(); - - if (main_thread_sp) { - m_threads.push_back(main_thread_sp); - SetCurrentThreadID(main_thread_sp->GetID()); - main_thread_sp->SetStoppedByExec(); - } else { - SetCurrentThreadID(LLDB_INVALID_THREAD_ID); - LLDB_LOG(log, - "pid {0} no main thread found, discarded all threads, " - "we're in a no-thread state!", - GetID()); - } + SetCurrentThreadID(main_thread->GetID()); + main_thread->SetStoppedByExec(); // Tell coordinator about about the "new" (since exec) stopped main thread. - ThreadWasCreated(*main_thread_sp); + ThreadWasCreated(*main_thread); // Let our delegate know we have just exec'd. NotifyDidExec(); - // If we have a main thread, indicate we are stopped. - assert(main_thread_sp && "exec called during ptraced process but no main " - "thread metadata tracked"); - // Let the process know we're stopped. - StopRunningThreads(main_thread_sp->GetID()); + StopRunningThreads(main_thread->GetID()); break; } @@ -685,10 +636,8 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, 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. + // 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()) @@ -700,18 +649,14 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, data, WIFEXITED(data), WIFSIGNALED(data), thread.GetID(), is_main_thread); - if (is_main_thread) - SetExitStatus(WaitStatus::Decode(data), true); 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. + // 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); @@ -725,7 +670,7 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, { // If a watchpoint was hit, report it uint32_t wp_index; - Status error = thread.GetRegisterContext()->GetWatchpointHitIndex( + Status error = thread.GetRegisterContext().GetWatchpointHitIndex( wp_index, (uintptr_t)info.si_addr); if (error.Fail()) LLDB_LOG(log, @@ -739,7 +684,7 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, // If a breakpoint was hit, report it uint32_t bp_index; - error = thread.GetRegisterContext()->GetHardwareBreakHitIndex( + error = thread.GetRegisterContext().GetHardwareBreakHitIndex( bp_index, (uintptr_t)info.si_addr); if (error.Fail()) LLDB_LOG(log, "received error while checking for hardware " @@ -762,7 +707,7 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, { // If a watchpoint was hit, report it uint32_t wp_index; - Status error = thread.GetRegisterContext()->GetWatchpointHitIndex( + Status error = thread.GetRegisterContext().GetWatchpointHitIndex( wp_index, LLDB_INVALID_ADDRESS); if (error.Fail()) LLDB_LOG(log, @@ -933,13 +878,13 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info, namespace { struct EmulatorBaton { - NativeProcessLinux *m_process; - NativeRegisterContext *m_reg_context; + NativeProcessLinux &m_process; + NativeRegisterContext &m_reg_context; // eRegisterKindDWARF -> RegsiterValue std::unordered_map m_register_values; - EmulatorBaton(NativeProcessLinux *process, NativeRegisterContext *reg_context) + EmulatorBaton(NativeProcessLinux &process, NativeRegisterContext ®_context) : m_process(process), m_reg_context(reg_context) {} }; @@ -951,7 +896,7 @@ static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, EmulatorBaton *emulator_baton = static_cast(baton); size_t bytes_read; - emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); + emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); return bytes_read; } @@ -971,11 +916,11 @@ static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, // 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( + emulator_baton->m_reg_context.GetRegisterInfo( eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); Status error = - emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); + emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); if (error.Success()) return true; @@ -999,17 +944,17 @@ static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, return length; } -static lldb::addr_t ReadFlags(NativeRegisterContext *regsiter_context) { - const RegisterInfo *flags_info = regsiter_context->GetRegisterInfo( +static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { + const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - return regsiter_context->ReadRegisterAsUnsigned(flags_info, - LLDB_INVALID_ADDRESS); + return regsiter_context.ReadRegisterAsUnsigned(flags_info, + LLDB_INVALID_ADDRESS); } Status NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { Status error; - NativeRegisterContextSP register_context_sp = thread.GetRegisterContext(); + NativeRegisterContext& register_context = thread.GetRegisterContext(); std::unique_ptr emulator_ap( EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, @@ -1018,7 +963,7 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { if (emulator_ap == nullptr) return Status("Instruction emulator not found!"); - EmulatorBaton baton(this, register_context_sp.get()); + EmulatorBaton baton(*this, register_context); emulator_ap->SetBaton(&baton); emulator_ap->SetReadMemCallback(&ReadMemoryCallback); emulator_ap->SetReadRegCallback(&ReadRegisterCallback); @@ -1031,9 +976,9 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { bool emulation_result = emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); - const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo( + const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - const RegisterInfo *reg_info_flags = register_context_sp->GetRegisterInfo( + const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); auto pc_it = @@ -1051,15 +996,14 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { if (flags_it != baton.m_register_values.end()) next_flags = flags_it->second.GetAsUInt64(); else - next_flags = ReadFlags(register_context_sp.get()); + 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_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize(); - next_flags = ReadFlags(register_context_sp.get()); + 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 @@ -1078,7 +1022,8 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { } 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::mipsel || + m_arch.GetMachine() == llvm::Triple::ppc64le) error = SetSoftwareBreakpoint(next_pc, 4); else { // No size hint is given for the next breakpoint @@ -1114,44 +1059,44 @@ Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) { bool software_single_step = !SupportHardwareSingleStepping(); if (software_single_step) { - for (auto thread_sp : m_threads) { - assert(thread_sp && "thread list should not contain NULL threads"); + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); const ResumeAction *const action = - resume_actions.GetActionForThread(thread_sp->GetID(), true); + resume_actions.GetActionForThread(thread->GetID(), true); if (action == nullptr) continue; if (action->state == eStateStepping) { Status error = SetupSoftwareSingleStepping( - static_cast(*thread_sp)); + static_cast(*thread)); if (error.Fail()) return error; } } } - for (auto thread_sp : m_threads) { - assert(thread_sp && "thread list should not contain NULL threads"); + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); const ResumeAction *const action = - resume_actions.GetActionForThread(thread_sp->GetID(), true); + resume_actions.GetActionForThread(thread->GetID(), true); if (action == nullptr) { LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), - thread_sp->GetID()); + thread->GetID()); continue; } LLDB_LOG(log, "processing resume action state {0} for pid {1} tid {2}", - action->state, GetID(), thread_sp->GetID()); + 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(*thread_sp), action->state, + ResumeThread(static_cast(*thread), action->state, signo); break; } @@ -1164,7 +1109,7 @@ Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) { return Status("NativeProcessLinux::%s (): unexpected state %s specified " "for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString(action->state), GetID(), - thread_sp->GetID()); + thread->GetID()); } } @@ -1190,8 +1135,8 @@ Status NativeProcessLinux::Detach() { if (GetID() == LLDB_INVALID_PROCESS_ID) return error; - for (auto thread_sp : m_threads) { - Status e = Detach(thread_sp->GetID()); + 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. @@ -1221,29 +1166,25 @@ Status NativeProcessLinux::Interrupt() { // the chosen thread that will be the stop-reason thread. Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - NativeThreadProtocolSP running_thread_sp; - NativeThreadProtocolSP stopped_thread_sp; + NativeThreadProtocol *running_thread = nullptr; + NativeThreadProtocol *stopped_thread = nullptr; LLDB_LOG(log, "selecting running thread for interrupt target"); - for (auto thread_sp : m_threads) { - // The thread shouldn't be null but lets just cover that here. - if (!thread_sp) - continue; - + 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_sp->GetState(); + const auto thread_state = thread->GetState(); if (thread_state == eStateRunning || thread_state == eStateStepping) { - running_thread_sp = thread_sp; + running_thread = thread.get(); break; - } else if (!stopped_thread_sp && StateIsStoppedState(thread_state, true)) { + } 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_sp = thread_sp; + stopped_thread = thread.get(); } } - if (!running_thread_sp && !stopped_thread_sp) { + 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); @@ -1251,14 +1192,14 @@ Status NativeProcessLinux::Interrupt() { return error; } - NativeThreadProtocolSP deferred_signal_thread_sp = - running_thread_sp ? running_thread_sp : stopped_thread_sp; + 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_sp ? "running" : "stopped", - deferred_signal_thread_sp->GetID()); + running_thread ? "running" : "stopped", + deferred_signal_thread->GetID()); - StopRunningThreads(deferred_signal_thread_sp->GetID()); + StopRunningThreads(deferred_signal_thread->GetID()); return Status(); } @@ -1568,17 +1509,13 @@ size_t NativeProcessLinux::UpdateThreads() { return m_threads.size(); } -bool NativeProcessLinux::GetArchitecture(ArchSpec &arch) const { - arch = m_arch; - return true; -} - Status NativeProcessLinux::GetSoftwareBreakpointPCOffset( uint32_t &actual_opcode_size) { // FIXME put this behind a breakpoint protocol class that can be // set per architecture. Need ARM, MIPS support here. static const uint8_t g_i386_opcode[] = {0xCC}; static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; + static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap switch (m_arch.GetMachine()) { case llvm::Triple::x86: @@ -1590,6 +1527,10 @@ Status NativeProcessLinux::GetSoftwareBreakpointPCOffset( actual_opcode_size = static_cast(sizeof(g_s390x_opcode)); return Status(); + case llvm::Triple::ppc64le: + actual_opcode_size = static_cast(sizeof(g_ppc64le_opcode)); + return Status(); + case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::mips64: @@ -1635,6 +1576,7 @@ Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode( static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00}; static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; + static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap switch (m_arch.GetMachine()) { case llvm::Triple::aarch64: @@ -1680,6 +1622,11 @@ Status NativeProcessLinux::GetSoftwareBreakpointTrapOpcode( actual_opcode_size = sizeof(g_s390x_opcode); return Status(); + case llvm::Triple::ppc64le: + trap_opcode_bytes = g_ppc64le_opcode; + actual_opcode_size = sizeof(g_ppc64le_opcode); + return Status(); + default: assert(false && "CPU type not supported!"); return Status("CPU type not supported"); @@ -1963,9 +1910,9 @@ Status NativeProcessLinux::Detach(lldb::tid_t tid) { } bool NativeProcessLinux::HasThreadNoLock(lldb::tid_t thread_id) { - for (auto thread_sp : m_threads) { - assert(thread_sp && "thread list should not contain NULL threads"); - if (thread_sp->GetID() == 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; } @@ -1994,7 +1941,7 @@ bool NativeProcessLinux::StopTrackingThread(lldb::tid_t thread_id) { return found; } -NativeThreadLinuxSP NativeProcessLinux::AddThread(lldb::tid_t thread_id) { +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); @@ -2005,8 +1952,7 @@ NativeThreadLinuxSP NativeProcessLinux::AddThread(lldb::tid_t thread_id) { if (m_threads.empty()) SetCurrentThreadID(thread_id); - auto thread_sp = std::make_shared(*this, thread_id); - m_threads.push_back(thread_sp); + m_threads.push_back(llvm::make_unique(*this, thread_id)); if (m_pt_proces_trace_id != LLDB_INVALID_UID) { auto traceMonitor = ProcessorTraceMonitor::Create( @@ -2022,7 +1968,7 @@ NativeThreadLinuxSP NativeProcessLinux::AddThread(lldb::tid_t thread_id) { } } - return thread_sp; + return static_cast(*m_threads.back()); } Status @@ -2033,12 +1979,7 @@ NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) { // Find out the size of a breakpoint (might depend on where we are in the // code). - NativeRegisterContextSP context_sp = thread.GetRegisterContext(); - if (!context_sp) { - error.SetErrorString("cannot get a NativeRegisterContext for the thread"); - LLDB_LOG(log, "failed: {0}", error); - return error; - } + NativeRegisterContext &context = thread.GetRegisterContext(); uint32_t breakpoint_size = 0; error = GetSoftwareBreakpointPCOffset(breakpoint_size); @@ -2050,8 +1991,7 @@ NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) { // First try probing for a breakpoint at a software breakpoint location: PC - // breakpoint size. - const lldb::addr_t initial_pc_addr = - context_sp->GetPCfromBreakpointLocation(); + const lldb::addr_t initial_pc_addr = context.GetPCfromBreakpointLocation(); lldb::addr_t breakpoint_addr = initial_pc_addr; if (breakpoint_size > 0) { // Do not allow breakpoint probe to wrap around. @@ -2098,7 +2038,7 @@ NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) { LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(), thread.GetID(), initial_pc_addr, breakpoint_addr); - error = context_sp->SetPC(breakpoint_addr); + error = context.SetPC(breakpoint_addr); if (error.Fail()) { LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(), thread.GetID(), error); @@ -2144,8 +2084,8 @@ Status NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef &file_name, return Status("No load address found for specified file."); } -NativeThreadLinuxSP NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { - return std::static_pointer_cast( +NativeThreadLinux *NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { + return static_cast( NativeProcessProtocol::GetThreadByID(tid)); } @@ -2200,9 +2140,9 @@ void NativeProcessLinux::StopRunningThreads(const lldb::tid_t 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_sp : m_threads) { - if (StateIsRunningState(thread_sp->GetState())) - static_pointer_cast(thread_sp)->RequestStop(); + for (const auto &thread : m_threads) { + if (StateIsRunningState(thread->GetState())) + static_cast(thread.get())->RequestStop(); } SignalIfAllThreadsStopped(); diff --git a/source/Plugins/Process/Linux/NativeProcessLinux.h b/source/Plugins/Process/Linux/NativeProcessLinux.h index c9ec002760f8..f078c1ac30e2 100644 --- a/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -13,12 +13,11 @@ #include #include -// Other libraries and framework includes -#include "lldb/Core/ArchSpec.h" #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" @@ -87,7 +86,7 @@ public: size_t UpdateThreads() override; - bool GetArchitecture(ArchSpec &arch) const override; + const ArchSpec &GetArchitecture() const override { return m_arch; } Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override; @@ -102,7 +101,7 @@ public: Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override; - NativeThreadLinuxSP GetThreadByID(lldb::tid_t id); + NativeThreadLinux *GetThreadByID(lldb::tid_t id); llvm::ErrorOr> GetAuxvData() const override { @@ -203,7 +202,7 @@ private: bool StopTrackingThread(lldb::tid_t thread_id); - NativeThreadLinuxSP AddThread(lldb::tid_t thread_id); + NativeThreadLinux &AddThread(lldb::tid_t thread_id); Status GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size); diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index 30f09f0c3a3f..c8a8355f9cb9 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -14,27 +14,19 @@ #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/Host/linux/Ptrace.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, uint32_t concrete_frame_idx, + NativeThreadProtocol &native_thread, RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, - reg_info_interface_p) {} + : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {} lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { - // Get the target process whose privileged thread was used for the register - // read. - lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; - - if (!m_thread.GetProcess().GetByteOrder(byte_order)) { - // FIXME log here - } - - return byte_order; + return m_thread.GetProcess().GetByteOrder(); } Status NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux.h index 26074a6ce0e3..2cea497b53bc 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.h @@ -10,10 +10,8 @@ #ifndef lldb_NativeRegisterContextLinux_h #define lldb_NativeRegisterContextLinux_h -#include "lldb/Host/common/NativeThreadProtocol.h" - -#include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeThreadProtocol.h" namespace lldb_private { namespace process_linux { @@ -21,20 +19,15 @@ namespace process_linux { class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo { public: NativeRegisterContextLinux(NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx, 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 NativeRegisterContextLinux * + // 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 CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); protected: lldb::ByteOrder GetByteOrder() const; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index 22b7d10869fe..cb05416cb6c3 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -11,15 +11,15 @@ #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/Core/RegisterValue.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" - #include #include @@ -95,20 +95,18 @@ static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { #if defined(__arm__) -NativeRegisterContextLinux * +std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) { - return new NativeRegisterContextLinux_arm(target_arch, native_thread, - concrete_frame_idx); + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return llvm::make_unique(target_arch, + native_thread); } #endif // defined(__arm__) NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) - : NativeRegisterContextLinux(native_thread, concrete_frame_idx, + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextLinux(native_thread, new RegisterInfoPOSIX_arm(target_arch)) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index ec99c05e1644..40e3b80eda74 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -23,8 +23,7 @@ class NativeProcessLinux; class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_arm(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); uint32_t GetRegisterSetCount() const override; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 7aad062e3f93..c483260a5b2c 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -112,26 +112,24 @@ static const RegisterSet g_reg_sets_arm64[k_num_register_sets] = { {"Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64}}; -NativeRegisterContextLinux * +std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) { + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: - return new NativeRegisterContextLinux_arm(target_arch, native_thread, - concrete_frame_idx); + return llvm::make_unique(target_arch, + native_thread); case llvm::Triple::aarch64: - return new NativeRegisterContextLinux_arm64(target_arch, native_thread, - concrete_frame_idx); + return llvm::make_unique(target_arch, + native_thread); default: llvm_unreachable("have no register context for architecture"); } } NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) - : NativeRegisterContextLinux(native_thread, concrete_frame_idx, + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextLinux(native_thread, new RegisterInfoPOSIX_arm64(target_arch)) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: @@ -872,12 +870,8 @@ Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); if (error.Success()) { - ArchSpec arch; - if (m_thread.GetProcess().GetArchitecture(arch)) - value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, - arch.GetByteOrder()); - else - error.SetErrorString("failed to get architecture"); + value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, + m_thread.GetProcess().GetByteOrder()); } } else { elf_gregset_t regs; @@ -889,12 +883,8 @@ Status NativeRegisterContextLinux_arm64::DoReadRegisterValue( error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); if (error.Success()) { - ArchSpec arch; - if (m_thread.GetProcess().GetArchitecture(arch)) - value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, - arch.GetByteOrder()); - else - error.SetErrorString("failed to get architecture"); + value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, + m_thread.GetProcess().GetByteOrder()); } } return error; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h index 9877dec37c48..ab3c881ead59 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -23,8 +23,7 @@ class NativeProcessLinux; class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_arm64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); uint32_t GetRegisterSetCount() const override; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index f35ff2be0d94..32c04a4374e6 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -80,12 +80,11 @@ struct pt_watch_regs default_watch_regs; using namespace lldb_private; using namespace lldb_private::process_linux; -NativeRegisterContextLinux * +std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) { - return new NativeRegisterContextLinux_mips64(target_arch, native_thread, - concrete_frame_idx); + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return llvm::make_unique(target_arch, + native_thread); } #define REG_CONTEXT_SIZE \ @@ -110,9 +109,8 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) - : NativeRegisterContextLinux(native_thread, concrete_frame_idx, + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextLinux(native_thread, CreateRegisterInfoInterface(target_arch)) { switch (target_arch.GetMachine()) { case llvm::Triple::mips: @@ -1033,13 +1031,11 @@ Status NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset, Status error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); if (error.Success()) { - lldb_private::ArchSpec arch; - if (m_thread.GetProcess().GetArchitecture(arch)) { - void *target_address = ((uint8_t *)®s) + offset + - 4 * (arch.GetMachine() == llvm::Triple::mips); - value.SetUInt(*(uint32_t *)target_address, size); - } else - error.SetErrorString("failed to get architecture"); + const lldb_private::ArchSpec &arch = + m_thread.GetProcess().GetArchitecture(); + void *target_address = ((uint8_t *)®s) + offset + + 4 * (arch.GetMachine() == llvm::Triple::mips); + value.SetUInt(*(uint32_t *)target_address, size); } return error; } diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h index 3e14da5a2725..c4e984a545bc 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h @@ -15,6 +15,7 @@ #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" #include "Plugins/Process/Utility/RegisterContext_mips.h" #include "Plugins/Process/Utility/lldb-mips-linux-register-enums.h" +#include #define MAX_NUM_WP 8 @@ -26,8 +27,7 @@ class NativeProcessLinux; class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_mips64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); uint32_t GetRegisterSetCount() const override; @@ -129,7 +129,7 @@ private: lldb::addr_t hw_addr_map[MAX_NUM_WP]; - IOVEC_mips m_iovec; + struct iovec m_iovec; }; } // namespace process_linux diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp new file mode 100644 index 000000000000..ea854dfa1dc6 --- /dev/null +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp @@ -0,0 +1,801 @@ +//===-- 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/Core/RegisterValue.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.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 +#include +#include + +#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, +}; + +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, +}; + +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, +}; + +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, +}; + +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::CreateHostNativeRegisterContextLinux( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + switch (target_arch.GetMachine()) { + case llvm::Triple::ppc64le: + return llvm::make_unique(target_arch, + native_thread); + default: + llvm_unreachable("have no register context for architecture"); + } +} + +NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextLinux(native_thread, + new RegisterInfoPOSIX_ppc64le(target_arch)) { + if (target_arch.GetMachine() != llvm::Triple::ppc64le) { + llvm_unreachable("Unhandled target architecture."); + } + + ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le)); + ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le)); + ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le)); + ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le)); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); +} + +uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const { + if (set_index < k_num_register_sets) + return &g_reg_sets_ppc64le[set_index]; + + return nullptr; +} + +uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) + count += g_reg_sets_ppc64le[set_index].num_registers; + return count; +} + +Status NativeRegisterContextLinux_ppc64le::ReadRegister( + const RegisterInfo *reg_info, RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (IsFPR(reg)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data from it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < sizeof m_fpr_ppc64le); + uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsVSX(reg)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + uint8_t *dst, *src; + dst = (uint8_t *)&value; + src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + dst += 8; + src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + reg_value.SetFromMemoryData(reg_info, &value, reg_info->byte_size, + eByteOrderLittle, error); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } + } else if (IsVMX(reg)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof m_vmx_ppc64le); + uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else if (IsGPR(reg)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset; + reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, + eByteOrderLittle, error); + } else { + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, read strategy unknown"); + } + + return error; +} + +Status NativeRegisterContextLinux_ppc64le::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg_index == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + if (IsGPR(reg_index)) { + error = ReadGPR(); + if (error.Fail()) + return error; + + uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteGPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsFPR(reg_index)) { + error = ReadFPR(); + if (error.Fail()) + return error; + + // Get pointer to m_fpr_ppc64le variable and set the data to it. + uint32_t fpr_offset = CalculateFprOffset(reg_info); + assert(fpr_offset < GetFPRSize()); + uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVMX(reg_index)) { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data to it. + uint32_t vmx_offset = CalculateVmxOffset(reg_info); + assert(vmx_offset < sizeof(m_vmx_ppc64le)); + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + + error = WriteVMX(); + if (error.Fail()) + return error; + + return Status(); + } + + if (IsVSX(reg_index)) { + uint32_t vsx_offset = CalculateVsxOffset(reg_info); + assert(vsx_offset < sizeof(m_vsx_ppc64le)); + + if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) { + error = ReadVSX(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + uint64_t value[2]; + ::memcpy(value, reg_value.GetBytes(), 16); + uint8_t *dst, *src; + src = (uint8_t *)value; + dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + src += 8; + dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2; + ::memcpy(dst, src, 8); + + WriteVSX(); + WriteFPR(); + } else { + error = ReadVMX(); + if (error.Fail()) + return error; + + // Get pointer to m_vmx_ppc64le variable and set the data from it. + uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2; + uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset; + ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize()); + WriteVMX(); + } + + return Status(); + } + + return Status("failed - register wasn't recognized to be a GPR, FPR, VSX " + "or VMX, write strategy unknown"); +} + +Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + if (!data_sp) + return Status("failed to allocate DataBufferHeap instance of size %" PRIu64, + REG_CONTEXT_SIZE); + + error = ReadGPR(); + if (error.Fail()) + return error; + + error = ReadFPR(); + if (error.Fail()) + return error; + + error = ReadVMX(); + if (error.Fail()) + return error; + + error = ReadVSX(); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + if (dst == nullptr) { + error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 + " returned a null pointer", + REG_CONTEXT_SIZE); + return error; + } + + ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize()); + dst += GetGPRSize(); + ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize()); + dst += GetFPRSize(); + ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le)); + dst += sizeof(m_vmx_ppc64le); + ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le)); + + return error; +} + +Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + + ::memcpy(&m_gpr_ppc64le, src, GetGPRSize()); + error = WriteGPR(); + + if (error.Fail()) + return error; + + src += GetGPRSize(); + ::memcpy(&m_fpr_ppc64le, src, GetFPRSize()); + + error = WriteFPR(); + if (error.Fail()) + return error; + + src += GetFPRSize(); + ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le)); + + error = WriteVMX(); + if (error.Fail()) + return error; + + src += sizeof(m_vmx_ppc64le); + ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le)); + error = WriteVSX(); + + return error; +} + +bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const { + return reg <= k_last_gpr_ppc64le; // GPR's come first. +} + +bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const { + return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le); +} + +Status NativeRegisterContextLinux_ppc64le::DoReadGPR( + void *buf, size_t buf_size) { + int regset = NT_PRSTATUS; + return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), + ®set, buf, buf_size); +} + +Status NativeRegisterContextLinux_ppc64le::DoWriteGPR( + void *buf, size_t buf_size) { + int regset = NT_PRSTATUS; + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), + ®set, buf, buf_size); +} + +Status NativeRegisterContextLinux_ppc64le::DoReadFPR(void *buf, + size_t buf_size) { + int regset = NT_FPREGSET; + return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), + ®set, buf, buf_size); +} + +Status NativeRegisterContextLinux_ppc64le::DoWriteFPR(void *buf, + size_t buf_size) { + int regset = NT_FPREGSET; + return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), + ®set, buf, buf_size); +} + +uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset; +} + +uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - + GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset; +} + +Status NativeRegisterContextLinux_ppc64le::ReadVMX() { + int regset = NT_PPC_VMX; + return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextLinux_ppc64le::WriteVMX() { + int regset = NT_PPC_VMX; + return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(), + ®set, &m_vmx_ppc64le, + sizeof(m_vmx_ppc64le)); +} + +Status NativeRegisterContextLinux_ppc64le::ReadVSX() { + int regset = NT_PPC_VSX; + return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +Status NativeRegisterContextLinux_ppc64le::WriteVSX() { + int regset = NT_PPC_VSX; + return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(), + ®set, &m_vsx_ppc64le, + sizeof(m_vsx_ppc64le)); +} + +bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) { + return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le); +} + +bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) { + return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le); +} + +uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return 0; + + LLDB_LOG(log, "{0}", m_max_hwp_supported); + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + Status error = ReadHardwareDebugInfo(); + + if (error.Fail()) + return LLDB_INVALID_INDEX32; + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + uint32_t rw_mode = 0; + + // Check if we are setting watchpoint other than read/write/access + // Update watchpoint flag to match ppc64le write-read bit configuration. + switch (watch_flags) { + case eWatchpointKindWrite: + rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE; + watch_flags = 2; + break; + case eWatchpointKindRead: + rw_mode = PPC_BREAKPOINT_TRIGGER_READ; + watch_flags = 1; + break; + case (eWatchpointKindRead | eWatchpointKindWrite): + rw_mode = PPC_BREAKPOINT_TRIGGER_RW; + break; + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 1 && size != 2 && size != 4 && size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. + // Below is a hack to recalculate address and size in order to + // make sure we can watch non 8-byte alligned addresses as well. + if (addr & 0x07) { + + addr_t begin = llvm::alignDown(addr, 8); + addr_t end = llvm::alignTo(addr + size, 8); + size = llvm::PowerOf2Ceil(end - begin); + + addr = addr & (~0x07); + } + + // Setup control value + control_value = watch_flags << 3; + control_value |= ((1 << size) - 1) << 5; + control_value |= (2 << 1) | 1; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if ((m_hwp_regs[i].control & 1) == 0) { + wp_index = i; // Mark last free slot + } else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + m_hwp_regs[wp_index].mode = rw_mode; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(); + + if (error.Fail()) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(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(m_hwp_regs[wp_index].slot); + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros(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(tempSlot); + + return false; + } + + return true; +} + +uint32_t +NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff; + if (llvm::isPowerOf2_32(control + 1)) { + return llvm::countPopulation(control); + } + + return 0; +} + +bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled( + uint32_t wp_index) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1); +} + +Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr <= watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + else + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + + return LLDB_INVALID_ADDRESS; +} + +Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return Status(); + } + + ::pid_t tid = m_thread.GetID(); + + struct ppc_debug_info hwdebug_info; + Status error; + + error = NativeProcessLinux::PtraceWrapper( + PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info)); + + if (error.Fail()) + return error; + + m_max_hwp_supported = hwdebug_info.num_data_bps; + m_max_hbp_supported = hwdebug_info.num_instruction_bps; + m_refresh_hwdebug_info = false; + + return error; +} + +Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() { + struct ppc_hw_breakpoint reg_state; + Status error; + long ret; + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + reg_state.addr = m_hwp_regs[i].address; + reg_state.trigger_type = m_hwp_regs[i].mode; + reg_state.version = 1; + reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT; + reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE; + reg_state.addr2 = 0; + reg_state.condition_value = 0; + + error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG, + m_thread.GetID(), 0, ®_state, + sizeof(reg_state), &ret); + + if (error.Fail()) + return error; + + m_hwp_regs[i].slot = ret; + } + + return error; +} + +#endif // defined(__powerpc64__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h new file mode 100644 index 000000000000..bb25af80d02c --- /dev/null +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.h @@ -0,0 +1,149 @@ +//===-- 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 "RegisterInfos_ppc64le.h" +#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT + +namespace lldb_private { +namespace process_linux { + +class NativeProcessLinux; + +class NativeRegisterContextLinux_ppc64le : public NativeRegisterContextLinux { +public: + NativeRegisterContextLinux_ppc64le(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + //------------------------------------------------------------------ + // Hardware watchpoint mangement 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 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 index c2a696e08bf9..021394ab154b 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp @@ -97,12 +97,11 @@ static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ -NativeRegisterContextLinux * +std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) { - return new NativeRegisterContextLinux_s390x(target_arch, native_thread, - concrete_frame_idx); + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return llvm::make_unique(target_arch, + native_thread); } // ---------------------------------------------------------------------------- @@ -117,9 +116,8 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) - : NativeRegisterContextLinux(native_thread, concrete_frame_idx, + 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()) { diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h index 3ffbaeeb0bba..57b1a0481512 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h @@ -24,8 +24,7 @@ class NativeProcessLinux; class NativeRegisterContextLinux_s390x : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_s390x(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); uint32_t GetRegisterSetCount() const override; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index e44e03b46b5c..84ffe9b6e420 100755 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -243,12 +243,11 @@ static inline unsigned int fxsr_regset(const ArchSpec &arch) { #define mask_XSTATE_BNDCFG (1ULL << 4) #define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG) -NativeRegisterContextLinux * +std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) { - return new NativeRegisterContextLinux_x86_64(target_arch, native_thread, - concrete_frame_idx); + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return std::unique_ptr( + new NativeRegisterContextLinux_x86_64(target_arch, native_thread)); } // ---------------------------------------------------------------------------- @@ -270,9 +269,8 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx) - : NativeRegisterContextLinux(native_thread, concrete_frame_idx, + 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() { @@ -334,11 +332,11 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( // 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.xstate.xsave; - m_iovec.iov_len = sizeof(m_fpr.xstate.xsave); + m_iovec.iov_base = &m_fpr; + m_iovec.iov_len = sizeof(m_fpr); // Clear out the FPR state. - ::memset(&m_fpr, 0, sizeof(FPR)); + ::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"); @@ -441,17 +439,14 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, if (byte_order != lldb::eByteOrderInvalid) { if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) - reg_value.SetBytes( - m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, - reg_info->byte_size, byte_order); + 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.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, - reg_info->byte_size, byte_order); + 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.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, - reg_info->byte_size, byte_order); + 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)) @@ -492,7 +487,7 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. + // 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,..)} @@ -530,6 +525,22 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } +void NativeRegisterContextLinux_x86_64::UpdateXSTATEforWrite( + uint32_t reg_index) { + XSAVE_HDR::XFeature &xstate_bv = m_fpr.xsave.header.xstate_bv; + if (IsFPR(reg_index)) { + // IsFPR considers both %st and %xmm registers as floating point, but these + // map to two features. Set both flags, just in case. + xstate_bv |= XSAVE_HDR::XFeature::FP | XSAVE_HDR::XFeature::SSE; + } else if (IsAVX(reg_index)) { + // Lower bytes of some %ymm registers are shared with %xmm registers. + xstate_bv |= XSAVE_HDR::XFeature::YMM | XSAVE_HDR::XFeature::SSE; + } else if (IsMPX(reg_index)) { + // MPX registers map to two XSAVE features. + xstate_bv |= XSAVE_HDR::XFeature::BNDREGS | XSAVE_HDR::XFeature::BNDCSR; + } +} + Status NativeRegisterContextLinux_x86_64::WriteRegister( const RegisterInfo *reg_info, const RegisterValue ®_value) { assert(reg_info && "reg_info is null"); @@ -540,25 +551,24 @@ Status NativeRegisterContextLinux_x86_64::WriteRegister( ? reg_info->name : ""); + 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.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); + ::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.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); + ::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.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, - reg_value.GetBytes(), reg_value.GetByteSize()); + ::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) { @@ -586,7 +596,7 @@ Status NativeRegisterContextLinux_x86_64::WriteRegister( return Status("CopyMPXtoXSTATE() failed"); } } else { - // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. + // 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 @@ -658,7 +668,7 @@ Status NativeRegisterContextLinux_x86_64::ReadAllRegisterValues( ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); if (m_xstate_type == XStateType::FXSAVE) - ::memcpy(dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + ::memcpy(dst, &m_fpr.fxsave, sizeof(m_fpr.fxsave)); else if (m_xstate_type == XStateType::XSAVE) { lldb::ByteOrder byte_order = GetByteOrder(); @@ -749,9 +759,9 @@ Status NativeRegisterContextLinux_x86_64::WriteAllRegisterValues( src += GetRegisterInfoInterface().GetGPRSize(); if (m_xstate_type == XStateType::FXSAVE) - ::memcpy(&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); + ::memcpy(&m_fpr.fxsave, src, sizeof(m_fpr.fxsave)); else if (m_xstate_type == XStateType::XSAVE) - ::memcpy(&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave)); + ::memcpy(&m_fpr.xsave, src, sizeof(m_fpr.xsave)); error = WriteFPR(); if (error.Fail()) @@ -805,12 +815,12 @@ bool NativeRegisterContextLinux_x86_64::IsCPUFeatureAvailable( 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.xstate.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX) + 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.xstate.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX) + if ((m_fpr.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX) return true; break; } @@ -847,11 +857,10 @@ Status NativeRegisterContextLinux_x86_64::WriteFPR() { switch (m_xstate_type) { case XStateType::FXSAVE: return WriteRegisterSet( - &m_iovec, sizeof(m_fpr.xstate.xsave), + &m_iovec, sizeof(m_fpr.fxsave), fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture())); case XStateType::XSAVE: - return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), - NT_X86_XSTATE); + return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xsave), NT_X86_XSTATE); default: return Status("Unrecognized FPR type."); } @@ -871,11 +880,11 @@ bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM( if (byte_order == lldb::eByteOrderLittle) { ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, - m_fpr.xstate.fxsave.xmm[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.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, + m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, sizeof(YMMHReg)); return true; } @@ -883,10 +892,10 @@ bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM( if (byte_order == lldb::eByteOrderBig) { ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof(XMMReg), - m_fpr.xstate.fxsave.xmm[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, - m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, + m_fpr.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes, sizeof(YMMHReg)); return true; } @@ -899,19 +908,19 @@ bool NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE( return false; if (byte_order == lldb::eByteOrderLittle) { - ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + ::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.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + ::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.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + ::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.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + ::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; } @@ -921,7 +930,7 @@ bool NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE( void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() { switch (m_xstate_type) { case XStateType::FXSAVE: - return &m_fpr.xstate.fxsave; + return &m_fpr.fxsave; case XStateType::XSAVE: return &m_iovec; default: @@ -932,7 +941,7 @@ void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() { size_t NativeRegisterContextLinux_x86_64::GetFPRSize() { switch (m_xstate_type) { case XStateType::FXSAVE: - return sizeof(m_fpr.xstate.fxsave); + return sizeof(m_fpr.fxsave); case XStateType::XSAVE: return sizeof(m_iovec); default: @@ -945,15 +954,14 @@ Status NativeRegisterContextLinux_x86_64::ReadFPR() { // 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.xstate.xsave), NT_X86_XSTATE); + 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.xstate.xsave), + &m_iovec, sizeof(m_fpr.xsave), fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture())); if (!error.Fail()) { m_xstate_type = XStateType::FXSAVE; @@ -975,11 +983,11 @@ bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) { 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.xstate.xsave.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.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, + m_fpr.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr)); } return true; @@ -990,10 +998,10 @@ bool NativeRegisterContextLinux_x86_64::CopyMPXtoXSTATE(uint32_t reg) { return false; if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) { - ::memcpy(m_fpr.xstate.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes, + ::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.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, + ::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; diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h index abb0dba4d91c..9dcf82f50a45 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -15,6 +15,7 @@ #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" #include "Plugins/Process/Utility/RegisterContext_x86.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include namespace lldb_private { namespace process_linux { @@ -24,8 +25,7 @@ class NativeProcessLinux; class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_x86_64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread, - uint32_t concrete_frame_idx); + NativeThreadProtocol &native_thread); uint32_t GetRegisterSetCount() const override; @@ -110,7 +110,7 @@ private: // Private member variables. mutable XStateType m_xstate_type; FPR m_fpr; // Extended States Area, named FPR for historical reasons. - IOVEC m_iovec; + struct iovec m_iovec; YMM m_ymm_set; MPX m_mpx_set; RegInfo m_reg_info; @@ -137,6 +137,8 @@ private: bool CopyMPXtoXSTATE(uint32_t reg); bool IsMPX(uint32_t reg_index) const; + + void UpdateXSTATEforWrite(uint32_t reg_index); }; } // namespace process_linux diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp index 5cd40941dcf8..0db3bd56b8e4 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -88,7 +88,11 @@ void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, NativeThreadLinux::NativeThreadLinux(NativeProcessLinux &process, lldb::tid_t tid) : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), - m_stop_info(), m_reg_context_sp(), m_stop_description() {} + m_stop_info(), + m_reg_context_up( + NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( + process.GetArchitecture(), *this)), + m_stop_description() {} std::string NativeThreadLinux::GetName() { NativeProcessLinux &process = GetProcess(); @@ -139,23 +143,6 @@ bool NativeThreadLinux::GetStopReason(ThreadStopInfo &stop_info, llvm_unreachable("unhandled StateType!"); } -NativeRegisterContextSP NativeThreadLinux::GetRegisterContext() { - // Return the register context if we already created it. - if (m_reg_context_sp) - return m_reg_context_sp; - - ArchSpec target_arch; - if (!m_process.GetArchitecture(target_arch)) - return NativeRegisterContextSP(); - - const uint32_t concrete_frame_idx = 0; - m_reg_context_sp.reset( - NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - target_arch, *this, concrete_frame_idx)); - - return m_reg_context_sp; -} - Status NativeThreadLinux::SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) { if (!hardware) @@ -165,8 +152,8 @@ Status NativeThreadLinux::SetWatchpoint(lldb::addr_t addr, size_t size, Status error = RemoveWatchpoint(addr); if (error.Fail()) return error; - NativeRegisterContextSP reg_ctx = GetRegisterContext(); - uint32_t wp_index = reg_ctx->SetHardwareWatchpoint(addr, size, watch_flags); + 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}); @@ -179,7 +166,7 @@ Status NativeThreadLinux::RemoveWatchpoint(lldb::addr_t addr) { return Status(); uint32_t wp_index = wp->second; m_watchpoint_index_map.erase(wp); - if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index)) + if (m_reg_context_up->ClearHardwareWatchpoint(wp_index)) return Status(); return Status("Clearing hardware watchpoint failed."); } @@ -193,8 +180,7 @@ Status NativeThreadLinux::SetHardwareBreakpoint(lldb::addr_t addr, if (error.Fail()) return error; - NativeRegisterContextSP reg_ctx = GetRegisterContext(); - uint32_t bp_index = reg_ctx->SetHardwareBreakpoint(addr, size); + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); if (bp_index == LLDB_INVALID_INDEX32) return Status("Setting hardware breakpoint failed."); @@ -209,7 +195,7 @@ Status NativeThreadLinux::RemoveHardwareBreakpoint(lldb::addr_t addr) { return Status(); uint32_t bp_index = bp->second; - if (GetRegisterContext()->ClearHardwareBreakpoint(bp_index)) { + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { m_hw_break_index_map.erase(bp); return Status(); } @@ -231,7 +217,7 @@ Status NativeThreadLinux::Resume(uint32_t signo) { NativeProcessLinux &process = GetProcess(); const auto &watchpoint_map = process.GetWatchpointMap(); - GetRegisterContext()->ClearAllHardwareWatchpoints(); + 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); @@ -243,7 +229,7 @@ Status NativeThreadLinux::Resume(uint32_t signo) { NativeProcessLinux &process = GetProcess(); const auto &hw_breakpoint_map = process.GetHardwareBreakpointMap(); - GetRegisterContext()->ClearAllHardwareBreakpoints(); + m_reg_context_up->ClearAllHardwareBreakpoints(); for (const auto &pair : hw_breakpoint_map) { const auto &bp = pair.second; SetHardwareBreakpoint(bp.m_addr, bp.m_size); @@ -365,7 +351,7 @@ void NativeThreadLinux::SetStoppedByWatchpoint(uint32_t wp_index) { lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); std::ostringstream ostr; - ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " "; + ostr << m_reg_context_up->GetWatchpointAddress(wp_index) << " "; ostr << wp_index; /* @@ -379,7 +365,7 @@ void NativeThreadLinux::SetStoppedByWatchpoint(uint32_t wp_index) { * stop-info * packet. */ - ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index); + ostr << " " << m_reg_context_up->GetWatchpointHitAddress(wp_index); m_stop_description = ostr.str(); diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.h b/source/Plugins/Process/Linux/NativeThreadLinux.h index 6ae87feffcda..a7c4e982012d 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.h +++ b/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -10,7 +10,8 @@ #ifndef liblldb_NativeThreadLinux_H_ #define liblldb_NativeThreadLinux_H_ -#include "SingleStepCheck.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" @@ -40,7 +41,9 @@ public: bool GetStopReason(ThreadStopInfo &stop_info, std::string &description) override; - NativeRegisterContextSP GetRegisterContext() 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; @@ -103,15 +106,13 @@ private: // --------------------------------------------------------------------- lldb::StateType m_state; ThreadStopInfo m_stop_info; - NativeRegisterContextSP m_reg_context_sp; + std::unique_ptr m_reg_context_up; std::string m_stop_description; using WatchpointIndexMap = std::map; WatchpointIndexMap m_watchpoint_index_map; WatchpointIndexMap m_hw_break_index_map; std::unique_ptr m_step_workaround; }; - -typedef std::shared_ptr NativeThreadLinuxSP; } // namespace process_linux } // namespace lldb_private -- cgit v1.2.3