diff options
Diffstat (limited to 'source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp')
| -rw-r--r-- | source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp | 638 |
1 files changed, 0 insertions, 638 deletions
diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp deleted file mode 100644 index 1bc916b69bcd..000000000000 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ /dev/null @@ -1,638 +0,0 @@ -//===-- NativeRegisterContextLinux_s390x.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(__s390x__) && defined(__linux__) - -#include "NativeRegisterContextLinux_s390x.h" -#include "Plugins/Process/Linux/NativeProcessLinux.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegisterValue.h" -#include "lldb/Utility/Status.h" - -#include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" - -#include <asm/ptrace.h> -#include <linux/uio.h> -#include <sys/ptrace.h> - -using namespace lldb_private; -using namespace lldb_private::process_linux; - -// ---------------------------------------------------------------------------- -// Private namespace. -// ---------------------------------------------------------------------------- - -namespace { -// s390x 64-bit general purpose registers. -static const uint32_t g_gpr_regnums_s390x[] = { - lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x, - lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x, - lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x, - lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x, - lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x, - lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x, - lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x, - lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x, - lldb_pswm_s390x, lldb_pswa_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) - - 1 == - k_num_gpr_registers_s390x, - "g_gpr_regnums_s390x has wrong number of register infos"); - -// s390x 64-bit floating point registers. -static const uint32_t g_fpu_regnums_s390x[] = { - lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x, - lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x, - lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x, - lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x, - lldb_fpc_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) - - 1 == - k_num_fpr_registers_s390x, - "g_fpu_regnums_s390x has wrong number of register infos"); - -// s390x Linux operating-system information. -static const uint32_t g_linux_regnums_s390x[] = { - lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert((sizeof(g_linux_regnums_s390x) / - sizeof(g_linux_regnums_s390x[0])) - - 1 == - k_num_linux_registers_s390x, - "g_linux_regnums_s390x has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_register_sets = 3 }; - -// Register sets for s390x 64-bit. -static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x, - g_gpr_regnums_s390x}, - {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x, - g_fpu_regnums_s390x}, - {"Linux Operating System Data", "linux", k_num_linux_registers_s390x, - g_linux_regnums_s390x}, -}; -} - -#define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4) - -// ---------------------------------------------------------------------------- -// Required ptrace defines. -// ---------------------------------------------------------------------------- - -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ - -std::unique_ptr<NativeRegisterContextLinux> -NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return llvm::make_unique<NativeRegisterContextLinux_s390x>(target_arch, - native_thread); -} - -// ---------------------------------------------------------------------------- -// NativeRegisterContextLinux_s390x members. -// ---------------------------------------------------------------------------- - -static RegisterInfoInterface * -CreateRegisterInfoInterface(const ArchSpec &target_arch) { - assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && - "Register setting path assumes this is a 64-bit host"); - return new RegisterContextLinux_s390x(target_arch); -} - -NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( - 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()) { - case llvm::Triple::systemz: - m_reg_info.num_registers = k_num_registers_s390x; - m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x; - m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x; - m_reg_info.last_gpr = k_last_gpr_s390x; - m_reg_info.first_fpr = k_first_fpr_s390x; - m_reg_info.last_fpr = k_last_fpr_s390x; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - // Clear out the watchpoint state. - m_watchpoint_addr = LLDB_INVALID_ADDRESS; -} - -uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const { - uint32_t sets = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (IsRegisterSetAvailable(set_index)) - ++sets; - } - - return sets; -} - -uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const { - uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - const RegisterSet *set = GetRegisterSet(set_index); - if (set) - count += set->num_registers; - } - return count; -} - -const RegisterSet * -NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const { - if (!IsRegisterSetAvailable(set_index)) - return nullptr; - - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::systemz: - return &g_reg_sets_s390x[set_index]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - - return nullptr; -} - -bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable( - uint32_t set_index) const { - return set_index < k_num_register_sets; -} - -bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const { - // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR - // register area. - return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x; -} - -bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const { - return (m_reg_info.first_fpr <= reg_index && - reg_index <= m_reg_info.last_fpr); -} - -Status -NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info, - RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg == LLDB_INVALID_REGNUM) - return Status("register \"%s\" is an internal-only lldb register, cannot " - "read directly", - reg_info->name); - - if (IsGPR(reg)) { - s390_regs regs; - Status error = DoReadGPR(®s, sizeof(regs)); - if (error.Fail()) - return error; - - uint8_t *src = (uint8_t *)®s + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); - switch (reg_info->byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return Status(); - } - - if (IsFPR(reg)) { - s390_fp_regs fp_regs; - Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); - if (error.Fail()) - return error; - - // byte_offset is just the offset within FPR, not the whole user area. - uint8_t *src = (uint8_t *)&fp_regs + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); - switch (reg_info->byte_size) { - case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; - case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return Status(); - } - - if (reg == lldb_last_break_s390x) { - uint64_t last_break; - Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8); - if (error.Fail()) - return error; - - reg_value.SetUInt64(last_break); - return Status(); - } - - if (reg == lldb_system_call_s390x) { - uint32_t system_call; - Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - if (error.Fail()) - return error; - - reg_value.SetUInt32(system_call); - return Status(); - } - - return Status("failed - register wasn't recognized"); -} - -Status NativeRegisterContextLinux_s390x::WriteRegister( - const RegisterInfo *reg_info, const RegisterValue ®_value) { - if (!reg_info) - return Status("reg_info NULL"); - - const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; - if (reg == LLDB_INVALID_REGNUM) - return Status("register \"%s\" is an internal-only lldb register, cannot " - "write directly", - reg_info->name); - - if (IsGPR(reg)) { - s390_regs regs; - Status error = DoReadGPR(®s, sizeof(regs)); - if (error.Fail()) - return error; - - uint8_t *dst = (uint8_t *)®s + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(regs)); - switch (reg_info->byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return DoWriteGPR(®s, sizeof(regs)); - } - - if (IsFPR(reg)) { - s390_fp_regs fp_regs; - Status error = DoReadFPR(&fp_regs, sizeof(fp_regs)); - if (error.Fail()) - return error; - - // byte_offset is just the offset within fp_regs, not the whole user area. - uint8_t *dst = (uint8_t *)&fp_regs + reg_info->byte_offset; - assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(fp_regs)); - switch (reg_info->byte_size) { - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled byte size: %" PRIu32, reg_info->byte_size); - } - return DoWriteFPR(&fp_regs, sizeof(fp_regs)); - } - - if (reg == lldb_last_break_s390x) { - return Status("The last break address is read-only"); - } - - if (reg == lldb_system_call_s390x) { - uint32_t system_call = reg_value.GetAsUInt32(); - return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - } - - return Status("failed - register wasn't recognized"); -} - -Status NativeRegisterContextLinux_s390x::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; - } - - 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; - } - - error = DoReadGPR(dst, sizeof(s390_regs)); - dst += sizeof(s390_regs); - if (error.Fail()) - return error; - - error = DoReadFPR(dst, sizeof(s390_fp_regs)); - dst += sizeof(s390_fp_regs); - if (error.Fail()) - return error; - - // Ignore errors if the regset is unsupported (happens on older kernels). - DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4); - dst += 4; - - // To enable inferior function calls while the process is stopped in an - // interrupted system call, we need to clear the system call flag. It will be - // restored to its original value by WriteAllRegisterValues. Again we ignore - // error if the regset is unsupported. - uint32_t system_call = 0; - DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4); - - return error; -} - -Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues( - const lldb::DataBufferSP &data_sp) { - Status error; - - if (!data_sp) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_s390x::%s invalid data_sp provided", - __FUNCTION__); - return error; - } - - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_s390x::%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_s390x::%s " - "DataBuffer::GetBytes() returned a null " - "pointer", - __FUNCTION__); - return error; - } - - error = DoWriteGPR(src, sizeof(s390_regs)); - src += sizeof(s390_regs); - if (error.Fail()) - return error; - - error = DoWriteFPR(src, sizeof(s390_fp_regs)); - src += sizeof(s390_fp_regs); - if (error.Fail()) - return error; - - // Ignore errors if the regset is unsupported (happens on older kernels). - DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4); - src += 4; - - return error; -} - -Status NativeRegisterContextLinux_s390x::DoReadRegisterValue( - uint32_t offset, const char *reg_name, uint32_t size, - RegisterValue &value) { - return Status("DoReadRegisterValue unsupported"); -} - -Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue( - uint32_t offset, const char *reg_name, const RegisterValue &value) { - return Status("DoWriteRegisterValue unsupported"); -} - -Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset, - void *buf, - size_t buf_size) { - ptrace_area parea; - parea.len = buf_size; - parea.process_addr = (addr_t)buf; - parea.kernel_addr = offset; - - return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA, - m_thread.GetID(), &parea); -} - -Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset, - const void *buf, - size_t buf_size) { - ptrace_area parea; - parea.len = buf_size; - parea.process_addr = (addr_t)buf; - parea.kernel_addr = offset; - - return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA, - m_thread.GetID(), &parea); -} - -Status NativeRegisterContextLinux_s390x::DoReadGPR(void *buf, size_t buf_size) { - assert(buf_size == sizeof(s390_regs)); - return PeekUserArea(offsetof(user_regs_struct, psw), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoWriteGPR(void *buf, - size_t buf_size) { - assert(buf_size == sizeof(s390_regs)); - return PokeUserArea(offsetof(user_regs_struct, psw), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoReadFPR(void *buf, size_t buf_size) { - assert(buf_size == sizeof(s390_fp_regs)); - return PeekUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoWriteFPR(void *buf, - size_t buf_size) { - assert(buf_size == sizeof(s390_fp_regs)); - return PokeUserArea(offsetof(user_regs_struct, fp_regs), buf, buf_size); -} - -Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset, - void *buf, - size_t buf_size) { - struct iovec iov; - iov.iov_base = buf; - iov.iov_len = buf_size; - - return ReadRegisterSet(&iov, buf_size, regset); -} - -Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset, - const void *buf, - size_t buf_size) { - struct iovec iov; - iov.iov_base = const_cast<void *>(buf); - iov.iov_len = buf_size; - - return WriteRegisterSet(&iov, buf_size, regset); -} - -Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - per_lowcore_bits per_lowcore; - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) { - is_hit = false; - return Status(); - } - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore), - &per_lowcore, sizeof(per_lowcore)); - if (error.Fail()) { - is_hit = false; - return error; - } - - is_hit = (per_lowcore.perc_storage_alteration == 1 && - per_lowcore.perc_store_real_address == 0); - - if (is_hit) { - // Do not report this watchpoint again. - memset(&per_lowcore, 0, sizeof(per_lowcore)); - PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore, - sizeof(per_lowcore)); - } - - return Status(); -} - -Status NativeRegisterContextLinux_s390x::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; - return error; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS; - - return Status(); -} - -bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint( - uint32_t wp_index) { - per_struct per_info; - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return false; - - per_info.control_regs.bits.em_storage_alteration = 0; - per_info.control_regs.bits.storage_alt_space_ctl = 0; - per_info.starting_addr = 0; - per_info.ending_addr = 0; - - error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return false; - - m_watchpoint_addr = LLDB_INVALID_ADDRESS; - return true; -} - -Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() { - if (ClearHardwareWatchpoint(0)) - return Status(); - return Status("Clearing all hardware watchpoints failed."); -} - -uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - per_struct per_info; - - if (watch_flags != 0x1) - return LLDB_INVALID_INDEX32; - - if (m_watchpoint_addr != LLDB_INVALID_ADDRESS) - return LLDB_INVALID_INDEX32; - - Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - per_info.control_regs.bits.em_storage_alteration = 1; - per_info.control_regs.bits.storage_alt_space_ctl = 1; - per_info.starting_addr = addr; - per_info.ending_addr = addr + size - 1; - - error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info, - sizeof(per_info)); - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - m_watchpoint_addr = addr; - return 0; -} - -lldb::addr_t -NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - return m_watchpoint_addr; -} - -uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() { - return 1; -} - -#endif // defined(__s390x__) && defined(__linux__) |
