| //===-- RegisterContextThreadMemory.cpp -----------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Target/OperatingSystem.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/Thread.h" | |
| #include "lldb/Utility/Status.h" | |
| #include "lldb/lldb-private.h" | |
| #include "RegisterContextThreadMemory.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| RegisterContextThreadMemory::RegisterContextThreadMemory( | |
| Thread &thread, lldb::addr_t register_data_addr) | |
| : RegisterContext(thread, 0), m_thread_wp(thread.shared_from_this()), | |
| m_reg_ctx_sp(), m_register_data_addr(register_data_addr), m_stop_id(0) {} | |
| RegisterContextThreadMemory::~RegisterContextThreadMemory() = default; | |
| void RegisterContextThreadMemory::UpdateRegisterContext() { | |
| std::lock_guard<std::mutex> lock(m_update_register_ctx_lock); | |
| ThreadSP thread_sp(m_thread_wp.lock()); | |
| if (thread_sp) { | |
| ProcessSP process_sp(thread_sp->GetProcess()); | |
| if (process_sp) { | |
| const uint32_t stop_id = process_sp->GetModID().GetStopID(); | |
| if (m_stop_id != stop_id) { | |
| m_stop_id = stop_id; | |
| m_reg_ctx_sp.reset(); | |
| } | |
| if (!m_reg_ctx_sp) { | |
| ThreadSP backing_thread_sp(thread_sp->GetBackingThread()); | |
| if (backing_thread_sp) { | |
| m_reg_ctx_sp = backing_thread_sp->GetRegisterContext(); | |
| } else { | |
| OperatingSystem *os = process_sp->GetOperatingSystem(); | |
| if (os->IsOperatingSystemPluginThread(thread_sp)) | |
| m_reg_ctx_sp = os->CreateRegisterContextForThread( | |
| thread_sp.get(), m_register_data_addr); | |
| } | |
| } | |
| } else { | |
| m_reg_ctx_sp.reset(); | |
| } | |
| } else { | |
| m_reg_ctx_sp.reset(); | |
| } | |
| } | |
| // Subclasses must override these functions | |
| void RegisterContextThreadMemory::InvalidateAllRegisters() { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| m_reg_ctx_sp->InvalidateAllRegisters(); | |
| } | |
| size_t RegisterContextThreadMemory::GetRegisterCount() { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->GetRegisterCount(); | |
| return 0; | |
| } | |
| const RegisterInfo * | |
| RegisterContextThreadMemory::GetRegisterInfoAtIndex(size_t reg) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg); | |
| return nullptr; | |
| } | |
| size_t RegisterContextThreadMemory::GetRegisterSetCount() { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->GetRegisterSetCount(); | |
| return 0; | |
| } | |
| const RegisterSet *RegisterContextThreadMemory::GetRegisterSet(size_t reg_set) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->GetRegisterSet(reg_set); | |
| return nullptr; | |
| } | |
| bool RegisterContextThreadMemory::ReadRegister(const RegisterInfo *reg_info, | |
| RegisterValue ®_value) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ReadRegister(reg_info, reg_value); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::WriteRegister( | |
| const RegisterInfo *reg_info, const RegisterValue ®_value) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->WriteRegister(reg_info, reg_value); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::ReadAllRegisterValues( | |
| lldb::WritableDataBufferSP &data_sp) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ReadAllRegisterValues(data_sp); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::ReadAllRegisterValues( | |
| lldb_private::RegisterCheckpoint ®_checkpoint) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ReadAllRegisterValues(reg_checkpoint); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::WriteAllRegisterValues( | |
| const lldb::DataBufferSP &data_sp) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->WriteAllRegisterValues(data_sp); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::WriteAllRegisterValues( | |
| const lldb_private::RegisterCheckpoint ®_checkpoint) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->WriteAllRegisterValues(reg_checkpoint); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::CopyFromRegisterContext( | |
| lldb::RegisterContextSP reg_ctx_sp) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp); | |
| return false; | |
| } | |
| uint32_t RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber( | |
| lldb::RegisterKind kind, uint32_t num) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num); | |
| return LLDB_INVALID_REGNUM; | |
| } | |
| uint32_t RegisterContextThreadMemory::NumSupportedHardwareBreakpoints() { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->NumSupportedHardwareBreakpoints(); | |
| return 0; | |
| } | |
| uint32_t RegisterContextThreadMemory::SetHardwareBreakpoint(lldb::addr_t addr, | |
| size_t size) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size); | |
| return 0; | |
| } | |
| bool RegisterContextThreadMemory::ClearHardwareBreakpoint(uint32_t hw_idx) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ClearHardwareBreakpoint(hw_idx); | |
| return false; | |
| } | |
| uint32_t RegisterContextThreadMemory::NumSupportedHardwareWatchpoints() { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->NumSupportedHardwareWatchpoints(); | |
| return 0; | |
| } | |
| uint32_t RegisterContextThreadMemory::SetHardwareWatchpoint(lldb::addr_t addr, | |
| size_t size, | |
| bool read, | |
| bool write) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write); | |
| return 0; | |
| } | |
| bool RegisterContextThreadMemory::ClearHardwareWatchpoint(uint32_t hw_index) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index); | |
| return false; | |
| } | |
| bool RegisterContextThreadMemory::HardwareSingleStep(bool enable) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->HardwareSingleStep(enable); | |
| return false; | |
| } | |
| Status RegisterContextThreadMemory::ReadRegisterValueFromMemory( | |
| const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, | |
| uint32_t src_len, RegisterValue ®_value) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->ReadRegisterValueFromMemory(reg_info, src_addr, | |
| src_len, reg_value); | |
| return Status::FromErrorString("invalid register context"); | |
| } | |
| Status RegisterContextThreadMemory::WriteRegisterValueToMemory( | |
| const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, | |
| uint32_t dst_len, const RegisterValue ®_value) { | |
| UpdateRegisterContext(); | |
| if (m_reg_ctx_sp) | |
| return m_reg_ctx_sp->WriteRegisterValueToMemory(reg_info, dst_addr, dst_len, | |
| reg_value); | |
| return Status::FromErrorString("invalid register context"); | |
| } |