diff options
Diffstat (limited to 'source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp')
| -rw-r--r-- | source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp | 1053 |
1 files changed, 0 insertions, 1053 deletions
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp deleted file mode 100644 index d641056a0440..000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -//===-- NativeRegisterContextLinux_mips64.cpp ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#if defined(__mips__) - -#include "NativeRegisterContextLinux_mips64.h" - - -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "Plugins/Process/Linux/Procfs.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" -#include "lldb/Core/EmulateInstruction.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-private-enumerations.h" -#define NT_MIPS_MSA 0x600 -#define CONFIG5_FRE (1 << 8) -#define SR_FR (1 << 26) -#define NUM_REGISTERS 32 - -#include <asm/ptrace.h> -#include <sys/ptrace.h> - -#ifndef PTRACE_GET_WATCH_REGS -enum pt_watch_style { pt_watch_style_mips32, pt_watch_style_mips64 }; -struct mips32_watch_regs { - uint32_t watchlo[8]; - uint16_t watchhi[8]; - uint16_t watch_masks[8]; - uint32_t num_valid; -} __attribute__((aligned(8))); - -struct mips64_watch_regs { - uint64_t watchlo[8]; - uint16_t watchhi[8]; - uint16_t watch_masks[8]; - uint32_t num_valid; -} __attribute__((aligned(8))); - -struct pt_watch_regs { - enum pt_watch_style style; - union { - struct mips32_watch_regs mips32; - struct mips64_watch_regs mips64; - }; -}; - -#define PTRACE_GET_WATCH_REGS 0xd0 -#define PTRACE_SET_WATCH_REGS 0xd1 -#endif - -#define W (1 << 0) -#define R (1 << 1) -#define I (1 << 2) - -#define IRW (I | R | W) - -#ifndef PTRACE_GETREGSET -#define PTRACE_GETREGSET 0x4204 -#endif -struct pt_watch_regs default_watch_regs; - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return llvm::make_unique<NativeRegisterContextLinux_mips64>(target_arch, - native_thread); -} - -#define REG_CONTEXT_SIZE \ - (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR_linux_mips) + \ - sizeof(MSA_linux_mips)) - -// ---------------------------------------------------------------------------- -// NativeRegisterContextLinux_mips64 members. -// ---------------------------------------------------------------------------- - -static RegisterInfoInterface * -CreateRegisterInfoInterface(const ArchSpec &target_arch) { - if ((target_arch.GetMachine() == llvm::Triple::mips) || - (target_arch.GetMachine() == llvm::Triple::mipsel)) { - // 32-bit hosts run with a RegisterContextLinux_mips context. - return new RegisterContextLinux_mips( - target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); - } else { - return new RegisterContextLinux_mips64( - target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); - } -} - -NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)) { - switch (target_arch.GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - m_reg_info.num_registers = k_num_registers_mips; - m_reg_info.num_gpr_registers = k_num_gpr_registers_mips; - m_reg_info.num_fpr_registers = k_num_fpr_registers_mips; - m_reg_info.last_gpr = k_last_gpr_mips; - m_reg_info.first_fpr = k_first_fpr_mips; - m_reg_info.last_fpr = k_last_fpr_mips; - m_reg_info.first_msa = k_first_msa_mips; - m_reg_info.last_msa = k_last_msa_mips; - break; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - m_reg_info.num_registers = k_num_registers_mips64; - m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64; - m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64; - m_reg_info.last_gpr = k_last_gpr_mips64; - m_reg_info.first_fpr = k_first_fpr_mips64; - m_reg_info.last_fpr = k_last_fpr_mips64; - m_reg_info.first_msa = k_first_msa_mips64; - m_reg_info.last_msa = k_last_msa_mips64; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - // Initialize m_iovec to point to the buffer and buffer size using the - // conventions of Berkeley style UIO structures, as required by PTRACE - // extensions. - m_iovec.iov_base = &m_msa; - m_iovec.iov_len = sizeof(MSA_linux_mips); - - // init h/w watchpoint addr map - for (int index = 0; index <= MAX_NUM_WP; index++) - hw_addr_map[index] = LLDB_INVALID_ADDRESS; - - ::memset(&m_gpr, 0, sizeof(GPR_linux_mips)); - ::memset(&m_fpr, 0, sizeof(FPR_linux_mips)); - ::memset(&m_msa, 0, sizeof(MSA_linux_mips)); -} - -uint32_t NativeRegisterContextLinux_mips64::GetRegisterSetCount() const { - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - const auto context = static_cast<const RegisterContextLinux_mips64 &> - (GetRegisterInfoInterface()); - return context.GetRegisterSetCount(); - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: { - const auto context = static_cast<const RegisterContextLinux_mips &> - (GetRegisterInfoInterface()); - return context.GetRegisterSetCount(); - } - default: - llvm_unreachable("Unhandled target architecture."); - } -} - -lldb::addr_t NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation( - lldb::addr_t fail_value) { - Status error; - RegisterValue pc_value; - lldb::addr_t pc = fail_value; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "Reading PC from breakpoint location"); - - // PC register is at index 34 of the register array - const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex(gpr_pc_mips64); - - error = ReadRegister(pc_info_p, pc_value); - if (error.Success()) { - pc = pc_value.GetAsUInt64(); - - // CAUSE register is at index 37 of the register array - const RegisterInfo *const cause_info_p = - GetRegisterInfoAtIndex(gpr_cause_mips64); - RegisterValue cause_value; - - ReadRegister(cause_info_p, cause_value); - - uint64_t cause = cause_value.GetAsUInt64(); - LLDB_LOG(log, "PC {0:x} cause {1:x}", pc, cause); - - /* - * The breakpoint might be in a delay slot. In this case PC points - * to the delayed branch instruction rather then the instruction - * in the delay slot. If the CAUSE.BD flag is set then adjust the - * PC based on the size of the branch instruction. - */ - if ((cause & (1 << 31)) != 0) { - lldb::addr_t branch_delay = 0; - branch_delay = - 4; // FIXME - Adjust according to size of branch instruction at PC - pc = pc + branch_delay; - pc_value.SetUInt64(pc); - WriteRegister(pc_info_p, pc_value); - LLDB_LOG(log, "New PC {0:x}", pc); - } - } - - return pc; -} - -const RegisterSet * -NativeRegisterContextLinux_mips64::GetRegisterSet(uint32_t set_index) const { - if (set_index >= GetRegisterSetCount()) - return nullptr; - - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - const auto context = static_cast<const RegisterContextLinux_mips64 &> - (GetRegisterInfoInterface()); - return context.GetRegisterSet(set_index); - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: { - const auto context = static_cast<const RegisterContextLinux_mips &> - (GetRegisterInfoInterface()); - return context.GetRegisterSet(set_index); - } - default: - llvm_unreachable("Unhandled target architecture."); - } -} - -lldb_private::Status -NativeRegisterContextLinux_mips64::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - Status error; - - if (!reg_info) { - error.SetErrorString("reg_info NULL"); - return error; - } - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - uint8_t byte_size = reg_info->byte_size; - if (reg == LLDB_INVALID_REGNUM) { - // This is likely an internal register for lldb use only and should not be - // directly queried. - error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " - "register, cannot read directly", - reg_info->name); - return error; - } - - if (IsMSA(reg) && !IsMSAAvailable()) { - error.SetErrorString("MSA not available on this processor"); - return error; - } - - if (IsMSA(reg) || IsFPR(reg)) { - uint8_t *src = nullptr; - lldbassert(reg_info->byte_offset < sizeof(UserArea)); - - error = ReadCP1(); - - if (!error.Success()) { - error.SetErrorString("failed to read co-processor 1 register"); - return error; - } - - if (IsFPR(reg)) { - if (IsFR0() && (byte_size != 4)) { - byte_size = 4; - uint8_t ptrace_index; - ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - src = ReturnFPOffset(ptrace_index, reg_info->byte_offset); - } else - src = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); - } else - src = (uint8_t *)&m_msa + reg_info->byte_offset - - (sizeof(m_gpr) + sizeof(m_fpr)); - switch (byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - case 16: - reg_value.SetBytes((const void *)src, 16, GetByteOrder()); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - } else { - error = ReadRegisterRaw(reg, reg_value); - } - - return error; -} - -lldb_private::Status NativeRegisterContextLinux_mips64::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - Status error; - - assert(reg_info && "reg_info is null"); - - const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; - - if (reg_index == LLDB_INVALID_REGNUM) - return Status("no lldb regnum for %s", reg_info && reg_info->name - ? reg_info->name - : "<unknown register>"); - - if (IsMSA(reg_index) && !IsMSAAvailable()) { - error.SetErrorString("MSA not available on this processor"); - return error; - } - - if (IsFPR(reg_index) || IsMSA(reg_index)) { - uint8_t *dst = nullptr; - uint64_t *src = nullptr; - uint8_t byte_size = reg_info->byte_size; - lldbassert(reg_info->byte_offset < sizeof(UserArea)); - - // Initialise the FP and MSA buffers by reading all co-processor 1 - // registers - ReadCP1(); - - if (IsFPR(reg_index)) { - if (IsFR0() && (byte_size != 4)) { - byte_size = 4; - uint8_t ptrace_index; - ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - dst = ReturnFPOffset(ptrace_index, reg_info->byte_offset); - } else - dst = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); - } else - dst = (uint8_t *)&m_msa + reg_info->byte_offset - - (sizeof(m_gpr) + sizeof(m_fpr)); - switch (byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - case 16: - src = (uint64_t *)reg_value.GetBytes(); - *(uint64_t *)dst = *src; - *(uint64_t *)(dst + 8) = *(src + 1); - break; - default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, - reg_info->byte_size); - break; - } - error = WriteCP1(); - if (!error.Success()) { - error.SetErrorString("failed to write co-processor 1 register"); - return error; - } - } else { - error = WriteRegisterRaw(reg_index, reg_value); - } - - return error; -} - -Status NativeRegisterContextLinux_mips64::ReadAllRegisterValues( - lldb::DataBufferSP &data_sp) { - Status error; - - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!data_sp) { - error.SetErrorStringWithFormat( - "failed to allocate DataBufferHeap instance of size %" PRIu64, - REG_CONTEXT_SIZE); - return error; - } - - error = ReadGPR(); - if (!error.Success()) { - error.SetErrorString("ReadGPR() failed"); - return error; - } - - error = ReadCP1(); - if (!error.Success()) { - error.SetErrorString("ReadCP1() failed"); - return error; - } - - uint8_t *dst = data_sp->GetBytes(); - if (dst == nullptr) { - error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64 - " returned a null pointer", - REG_CONTEXT_SIZE); - return error; - } - - ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); - dst += GetRegisterInfoInterface().GetGPRSize(); - - ::memcpy(dst, &m_fpr, GetFPRSize()); - dst += GetFPRSize(); - - ::memcpy(dst, &m_msa, sizeof(MSA_linux_mips)); - - return error; -} - -Status NativeRegisterContextLinux_mips64::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - - uint8_t *src = data_sp->GetBytes(); - if (src == nullptr) { - error.SetErrorStringWithFormat("NativeRegisterContextLinux_mips64::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - - ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); - src += GetRegisterInfoInterface().GetGPRSize(); - - ::memcpy(&m_fpr, src, GetFPRSize()); - src += GetFPRSize(); - - ::memcpy(&m_msa, src, sizeof(MSA_linux_mips)); - - error = WriteGPR(); - if (!error.Success()) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s WriteGPR() failed", - __FUNCTION__); - return error; - } - - error = WriteCP1(); - if (!error.Success()) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_mips64::%s WriteCP1() failed", - __FUNCTION__); - return error; - } - - return error; -} - -Status NativeRegisterContextLinux_mips64::ReadCP1() { - Status error; - - uint8_t *src = nullptr; - uint8_t *dst = nullptr; - - lldb::ByteOrder byte_order = GetByteOrder(); - - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - - if (IsMSAAvailable()) { - error = NativeRegisterContextLinux::ReadRegisterSet( - &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); - src = (uint8_t *)&m_msa + (IsBigEndian * 8); - dst = (uint8_t *)&m_fpr; - for (int i = 0; i < NUM_REGISTERS; i++) { - // Copy fp values from msa buffer fetched via ptrace - *(uint64_t *)dst = *(uint64_t *)src; - src = src + 16; - dst = dst + 8; - } - m_fpr.fir = m_msa.fir; - m_fpr.fcsr = m_msa.fcsr; - m_fpr.config5 = m_msa.config5; - } else { - error = NativeRegisterContextLinux::ReadFPR(); - } - return error; -} - -uint8_t * -NativeRegisterContextLinux_mips64::ReturnFPOffset(uint8_t reg_index, - uint32_t byte_offset) { - - uint8_t *fp_buffer_ptr = nullptr; - lldb::ByteOrder byte_order = GetByteOrder(); - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - if (reg_index % 2) { - uint8_t offset_diff = (IsBigEndian) ? 8 : 4; - fp_buffer_ptr = - (uint8_t *)&m_fpr + byte_offset - offset_diff - sizeof(m_gpr); - } else { - fp_buffer_ptr = - (uint8_t *)&m_fpr + byte_offset + 4 * (IsBigEndian) - sizeof(m_gpr); - } - return fp_buffer_ptr; -} - -Status NativeRegisterContextLinux_mips64::WriteCP1() { - Status error; - - uint8_t *src = nullptr; - uint8_t *dst = nullptr; - - lldb::ByteOrder byte_order = GetByteOrder(); - - bool IsBigEndian = (byte_order == lldb::eByteOrderBig); - - if (IsMSAAvailable()) { - dst = (uint8_t *)&m_msa + (IsBigEndian * 8); - src = (uint8_t *)&m_fpr; - for (int i = 0; i < NUM_REGISTERS; i++) { - // Copy fp values to msa buffer for ptrace - *(uint64_t *)dst = *(uint64_t *)src; - dst = dst + 16; - src = src + 8; - } - m_msa.fir = m_fpr.fir; - m_msa.fcsr = m_fpr.fcsr; - m_msa.config5 = m_fpr.config5; - error = NativeRegisterContextLinux::WriteRegisterSet( - &m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); - } else { - error = NativeRegisterContextLinux::WriteFPR(); - } - - return error; -} - -bool NativeRegisterContextLinux_mips64::IsFR0() { - const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex(gpr_sr_mips64); - - RegisterValue reg_value; - ReadRegister(reg_info_p, reg_value); - - uint64_t value = reg_value.GetAsUInt64(); - - return (!(value & SR_FR)); -} - -bool NativeRegisterContextLinux_mips64::IsFRE() { - const RegisterInfo *const reg_info_p = - GetRegisterInfoAtIndex(gpr_config5_mips64); - - RegisterValue reg_value; - ReadRegister(reg_info_p, reg_value); - - uint64_t config5 = reg_value.GetAsUInt64(); - - return (config5 & CONFIG5_FRE); -} - -bool NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const { - return (m_reg_info.first_fpr <= reg_index && - reg_index <= m_reg_info.last_fpr); -} - -static uint32_t GetWatchHi(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watchhi[index]; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watchhi[index]; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static void SetWatchHi(struct pt_watch_regs *regs, uint32_t index, - uint16_t value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - regs->mips32.watchhi[index] = value; - else if (regs->style == pt_watch_style_mips64) - regs->mips64.watchhi[index] = value; - LLDB_LOG(log, "Invalid watch register style"); - return; -} - -static lldb::addr_t GetWatchLo(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watchlo[index]; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watchlo[index]; - LLDB_LOG(log, "Invalid watch register style"); - return LLDB_INVALID_ADDRESS; -} - -static void SetWatchLo(struct pt_watch_regs *regs, uint32_t index, - uint64_t value) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - regs->mips32.watchlo[index] = (uint32_t)value; - else if (regs->style == pt_watch_style_mips64) - regs->mips64.watchlo[index] = value; - else - LLDB_LOG(log, "Invalid watch register style"); -} - -static uint32_t GetIRWMask(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watch_masks[index] & IRW; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watch_masks[index] & IRW; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static uint32_t GetRegMask(struct pt_watch_regs *regs, uint32_t index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - if (regs->style == pt_watch_style_mips32) - return regs->mips32.watch_masks[index] & ~IRW; - else if (regs->style == pt_watch_style_mips64) - return regs->mips64.watch_masks[index] & ~IRW; - LLDB_LOG(log, "Invalid watch register style"); - return 0; -} - -static lldb::addr_t GetRangeMask(lldb::addr_t mask) { - lldb::addr_t mask_bit = 1; - while (mask_bit < mask) { - mask = mask | mask_bit; - mask_bit <<= 1; - } - return mask; -} - -static int GetVacantWatchIndex(struct pt_watch_regs *regs, lldb::addr_t addr, - uint32_t size, uint32_t irw, - uint32_t num_valid) { - lldb::addr_t last_byte = addr + size - 1; - lldb::addr_t mask = GetRangeMask(addr ^ last_byte) | IRW; - lldb::addr_t base_addr = addr & ~mask; - - // Check if this address is already watched by previous watch points. - lldb::addr_t lo; - uint16_t hi; - uint32_t vacant_watches = 0; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(regs, index); - if (lo != 0 && irw == ((uint32_t)lo & irw)) { - hi = GetWatchHi(regs, index) | IRW; - lo &= ~(lldb::addr_t)hi; - if (addr >= lo && last_byte <= (lo + hi)) - return index; - } else - vacant_watches++; - } - - // Now try to find a vacant index - if (vacant_watches > 0) { - vacant_watches = 0; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(regs, index); - if (lo == 0 && irw == (GetIRWMask(regs, index) & irw)) { - if (mask <= (GetRegMask(regs, index) | IRW)) { - // It fits, we can use it. - SetWatchLo(regs, index, base_addr | irw); - SetWatchHi(regs, index, mask & ~IRW); - return index; - } else { - // It doesn't fit, but has the proper IRW capabilities - vacant_watches++; - } - } - } - - if (vacant_watches > 1) { - // Split this watchpoint accross several registers - struct pt_watch_regs regs_copy; - regs_copy = *regs; - lldb::addr_t break_addr; - uint32_t segment_size; - for (uint32_t index = 0; index < num_valid; index++) { - lo = GetWatchLo(®s_copy, index); - hi = GetRegMask(®s_copy, index) | IRW; - if (lo == 0 && irw == (hi & irw)) { - lo = addr & ~(lldb::addr_t)hi; - break_addr = lo + hi + 1; - if (break_addr >= addr + size) - segment_size = size; - else - segment_size = break_addr - addr; - mask = GetRangeMask(addr ^ (addr + segment_size - 1)); - SetWatchLo(®s_copy, index, (addr & ~mask) | irw); - SetWatchHi(®s_copy, index, mask & ~IRW); - if (break_addr >= addr + size) { - *regs = regs_copy; - return index; - } - size = addr + size - break_addr; - addr = break_addr; - } - } - } - } - return LLDB_INVALID_INDEX32; -} - -bool NativeRegisterContextLinux_mips64::IsMSA(uint32_t reg_index) const { - return (m_reg_info.first_msa <= reg_index && - reg_index <= m_reg_info.last_msa); -} - -bool NativeRegisterContextLinux_mips64::IsMSAAvailable() { - MSA_linux_mips msa_buf; - unsigned int regset = NT_MIPS_MSA; - - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGSET, Host::GetCurrentProcessID(), - static_cast<void *>(®set), &msa_buf, sizeof(MSA_linux_mips)); - - if (error.Success() && msa_buf.mir) { - return true; - } - - return false; -} - -Status NativeRegisterContextLinux_mips64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // reading the current state of watch regs - struct pt_watch_regs watch_readback; - Status error = DoReadWatchPointRegisterValue( - m_thread.GetID(), static_cast<void *>(&watch_readback)); - - if (GetWatchHi(&watch_readback, wp_index) & (IRW)) { - // clear hit flag in watchhi - SetWatchHi(&watch_readback, wp_index, - (GetWatchHi(&watch_readback, wp_index) & ~(IRW))); - DoWriteWatchPointRegisterValue(m_thread.GetID(), - static_cast<void *>(&watch_readback)); - - is_hit = true; - return error; - } - is_hit = false; - return error; -} - -Status NativeRegisterContextLinux_mips64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_mips64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - is_vacant = false; - return Status("MIPS TODO: " - "NativeRegisterContextLinux_mips64::IsWatchpointVacant not " - "implemented"); -} - -bool NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - struct pt_watch_regs regs; - // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - if (regs.style == pt_watch_style_mips32) { - regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index]; - regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index]; - regs.mips32.watch_masks[wp_index] = - default_watch_regs.mips32.watch_masks[wp_index]; - } else // pt_watch_style_mips64 - { - regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index]; - regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index]; - regs.mips64.watch_masks[wp_index] = - default_watch_regs.mips64.watch_masks[wp_index]; - } - - Status error = DoWriteWatchPointRegisterValue(m_thread.GetID(), - static_cast<void *>(®s)); - if (!error.Fail()) { - hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS; - return true; - } - return false; -} - -Status NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() { - return DoWriteWatchPointRegisterValue( - m_thread.GetID(), static_cast<void *>(&default_watch_regs)); -} - -Status NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - Status error; - error.SetErrorString("MIPS TODO: " - "NativeRegisterContextLinux_mips64::" - "SetHardwareWatchpointWithIndex not implemented"); - return error; -} - -uint32_t NativeRegisterContextLinux_mips64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - struct pt_watch_regs regs; - - // First reading the current state of watch regs - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - // Try if a new watch point fits in this state - int index = GetVacantWatchIndex(®s, addr, size, watch_flags, - NumSupportedHardwareWatchpoints()); - - // New watchpoint doesn't fit - if (index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // It fits, so we go ahead with updating the state of watch regs - DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - - // Storing exact address - hw_addr_map[index] = addr; - return index; -} - -lldb::addr_t -NativeRegisterContextLinux_mips64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - - return hw_addr_map[wp_index]; -} - -struct EmulatorBaton { - lldb::addr_t m_watch_hit_addr; - NativeProcessLinux *m_process; - NativeRegisterContext *m_reg_context; - - EmulatorBaton(NativeProcessLinux *process, NativeRegisterContext *reg_context) - : m_watch_hit_addr(LLDB_INVALID_ADDRESS), m_process(process), - m_reg_context(reg_context) {} -}; - -static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, void *dst, size_t length) { - size_t bytes_read; - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); - return bytes_read; -} - -static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, const void *dst, - size_t length) { - return length; -} - -static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, - const RegisterInfo *reg_info, - RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - - const RegisterInfo *full_reg_info = - emulator_baton->m_reg_context->GetRegisterInfo( - lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]); - - Status error = - emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); - if (error.Success()) - return true; - - return false; -} - -static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - const RegisterInfo *reg_info, - const RegisterValue ®_value) { - if (reg_info->kinds[lldb::eRegisterKindDWARF] == dwarf_bad_mips64) { - EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); - emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64(); - } - - return true; -} - -/* - * MIPS Linux kernel returns a masked address (last 3bits are masked) - * when a HW watchpoint is hit. However user may not have set a watchpoint - * on this address. Emulate instruction at PC and find the base address of - * the load/store instruction. This will give the exact address used to - * read/write the variable. Send this exact address to client so that - * it can decide to stop or continue the thread. -*/ -lldb::addr_t -NativeRegisterContextLinux_mips64::GetWatchpointHitAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - - lldb_private::ArchSpec arch; - arch = GetRegisterInfoInterface().GetTargetArchitecture(); - std::unique_ptr<EmulateInstruction> emulator_ap( - EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny, - nullptr)); - - if (emulator_ap == nullptr) - return LLDB_INVALID_ADDRESS; - - EmulatorBaton baton( - static_cast<NativeProcessLinux *>(&m_thread.GetProcess()), this); - emulator_ap->SetBaton(&baton); - emulator_ap->SetReadMemCallback(&ReadMemoryCallback); - emulator_ap->SetReadRegCallback(&ReadRegisterCallback); - emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); - emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); - - if (!emulator_ap->ReadInstruction()) - return LLDB_INVALID_ADDRESS; - - if (emulator_ap->EvaluateInstruction(lldb::eEmulateInstructionOptionNone)) - return baton.m_watch_hit_addr; - - return LLDB_INVALID_ADDRESS; -} - -uint32_t NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - struct pt_watch_regs regs; - static int num_valid = 0; - if (!num_valid) { - DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast<void *>(®s)); - default_watch_regs = - regs; // Keeping default watch regs values for future use - switch (regs.style) { - case pt_watch_style_mips32: - num_valid = regs.mips32.num_valid; // Using num_valid as cache - return num_valid; - case pt_watch_style_mips64: - num_valid = regs.mips64.num_valid; - return num_valid; - } - LLDB_LOG(log, "Invalid watch register style"); - return 0; - } - return num_valid; -} - -Status -NativeRegisterContextLinux_mips64::ReadRegisterRaw(uint32_t reg_index, - RegisterValue &value) { - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - - if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); - - uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - - if ((offset == ptrace_sr_mips) || (offset == ptrace_config5_mips)) - return Read_SR_Config(reg_info->byte_offset, reg_info->name, - reg_info->byte_size, value); - - return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size, - value); -} - -Status NativeRegisterContextLinux_mips64::WriteRegisterRaw( - uint32_t reg_index, const RegisterValue &value) { - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - - if (!reg_info) - return Status("register %" PRIu32 " not found", reg_index); - - if (reg_info->invalidate_regs) - lldbassert(false && "reg_info->invalidate_regs is unhandled"); - - uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; - return DoWriteRegisterValue(offset, reg_info->name, value); -} - -Status NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset, - const char *reg_name, - uint32_t size, - RegisterValue &value) { - GPR_linux_mips regs; - ::memset(®s, 0, sizeof(GPR_linux_mips)); - - Status error = NativeProcessLinux::PtraceWrapper( - PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); - if (error.Success()) { - 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; -} - -Status NativeRegisterContextLinux_mips64::DoReadWatchPointRegisterValue( - lldb::tid_t tid, void *watch_readback) { - return NativeProcessLinux::PtraceWrapper(PTRACE_GET_WATCH_REGS, - m_thread.GetID(), watch_readback); -} - -Status NativeRegisterContextLinux_mips64::DoWriteWatchPointRegisterValue( - lldb::tid_t tid, void *watch_reg_value) { - return NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS, - m_thread.GetID(), watch_reg_value); -} - -#endif // defined (__mips__) |
