1d409305fSDimitry Andric //===-- NativeRegisterContextFreeBSD_powerpc.cpp --------------------------===// 2d409305fSDimitry Andric // 3d409305fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d409305fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5d409305fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d409305fSDimitry Andric // 7d409305fSDimitry Andric //===----------------------------------------------------------------------===// 8d409305fSDimitry Andric 9d409305fSDimitry Andric #if defined(__powerpc__) 10d409305fSDimitry Andric 11d409305fSDimitry Andric #include "NativeRegisterContextFreeBSD_powerpc.h" 12d409305fSDimitry Andric 13d409305fSDimitry Andric #include "lldb/Host/HostInfo.h" 14d409305fSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 15d409305fSDimitry Andric #include "lldb/Utility/RegisterValue.h" 16d409305fSDimitry Andric #include "lldb/Utility/Status.h" 17d409305fSDimitry Andric 18d409305fSDimitry Andric #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" 19d409305fSDimitry Andric // for register enum definitions 20d409305fSDimitry Andric #include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" 21d409305fSDimitry Andric 22d409305fSDimitry Andric // clang-format off 23d409305fSDimitry Andric #include <sys/param.h> 24d409305fSDimitry Andric #include <sys/ptrace.h> 25d409305fSDimitry Andric #include <sys/types.h> 26d409305fSDimitry Andric // clang-format on 27bdd1243dSDimitry Andric #include <optional> 28d409305fSDimitry Andric 29d409305fSDimitry Andric using namespace lldb; 30d409305fSDimitry Andric using namespace lldb_private; 31d409305fSDimitry Andric using namespace lldb_private::process_freebsd; 32d409305fSDimitry Andric 33d409305fSDimitry Andric static const uint32_t g_gpr_regnums[] = { 34d409305fSDimitry Andric gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc, 35d409305fSDimitry Andric gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc, 36d409305fSDimitry Andric gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc, 37d409305fSDimitry Andric gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc, 38d409305fSDimitry Andric gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc, 39d409305fSDimitry Andric gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc, 40d409305fSDimitry Andric gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc, 41d409305fSDimitry Andric gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc, 42d409305fSDimitry Andric gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc, 43d409305fSDimitry Andric gpr_pc_powerpc, 44d409305fSDimitry Andric }; 45d409305fSDimitry Andric 46d409305fSDimitry Andric static const uint32_t g_fpr_regnums[] = { 47d409305fSDimitry Andric fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc, 48d409305fSDimitry Andric fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc, 49d409305fSDimitry Andric fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc, 50d409305fSDimitry Andric fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc, 51d409305fSDimitry Andric fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc, 52d409305fSDimitry Andric fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc, 53d409305fSDimitry Andric fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc, 54d409305fSDimitry Andric fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc, 55d409305fSDimitry Andric fpr_fpscr_powerpc, 56d409305fSDimitry Andric }; 57d409305fSDimitry Andric 58d409305fSDimitry Andric // Number of register sets provided by this context. 59d409305fSDimitry Andric enum { k_num_register_sets = 2 }; 60d409305fSDimitry Andric 61d409305fSDimitry Andric static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = { 62d409305fSDimitry Andric {"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, 63d409305fSDimitry Andric g_gpr_regnums}, 64d409305fSDimitry Andric {"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, 65d409305fSDimitry Andric g_fpr_regnums}, 66d409305fSDimitry Andric }; 67d409305fSDimitry Andric 68d409305fSDimitry Andric NativeRegisterContextFreeBSD * 69d409305fSDimitry Andric NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( 70*0fca6ea1SDimitry Andric const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { 71d409305fSDimitry Andric return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread); 72d409305fSDimitry Andric } 73d409305fSDimitry Andric 74d409305fSDimitry Andric static RegisterInfoInterface * 75d409305fSDimitry Andric CreateRegisterInfoInterface(const ArchSpec &target_arch) { 76d409305fSDimitry Andric if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { 77d409305fSDimitry Andric return new RegisterContextFreeBSD_powerpc32(target_arch); 78d409305fSDimitry Andric } else { 79d409305fSDimitry Andric assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && 80d409305fSDimitry Andric "Register setting path assumes this is a 64-bit host"); 81d409305fSDimitry Andric return new RegisterContextFreeBSD_powerpc64(target_arch); 82d409305fSDimitry Andric } 83d409305fSDimitry Andric } 84d409305fSDimitry Andric 85d409305fSDimitry Andric NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc( 86*0fca6ea1SDimitry Andric const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) 87d409305fSDimitry Andric : NativeRegisterContextRegisterInfo( 88d409305fSDimitry Andric native_thread, CreateRegisterInfoInterface(target_arch)) {} 89d409305fSDimitry Andric 90d409305fSDimitry Andric RegisterContextFreeBSD_powerpc & 91d409305fSDimitry Andric NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const { 92d409305fSDimitry Andric return static_cast<RegisterContextFreeBSD_powerpc &>( 93d409305fSDimitry Andric *m_register_info_interface_up); 94d409305fSDimitry Andric } 95d409305fSDimitry Andric 96d409305fSDimitry Andric uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const { 97d409305fSDimitry Andric return k_num_register_sets; 98d409305fSDimitry Andric } 99d409305fSDimitry Andric 100d409305fSDimitry Andric const RegisterSet * 101d409305fSDimitry Andric NativeRegisterContextFreeBSD_powerpc::GetRegisterSet(uint32_t set_index) const { 102d409305fSDimitry Andric switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 103d409305fSDimitry Andric case llvm::Triple::ppc: 104d409305fSDimitry Andric return &g_reg_sets_powerpc[set_index]; 105d409305fSDimitry Andric default: 106d409305fSDimitry Andric llvm_unreachable("Unhandled target architecture."); 107d409305fSDimitry Andric } 108d409305fSDimitry Andric } 109d409305fSDimitry Andric 110bdd1243dSDimitry Andric std::optional<NativeRegisterContextFreeBSD_powerpc::RegSetKind> 111d409305fSDimitry Andric NativeRegisterContextFreeBSD_powerpc::GetSetForNativeRegNum( 112d409305fSDimitry Andric uint32_t reg_num) const { 113d409305fSDimitry Andric switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { 114d409305fSDimitry Andric case llvm::Triple::ppc: 115d409305fSDimitry Andric if (reg_num >= k_first_gpr_powerpc && reg_num <= k_last_gpr_powerpc) 116d409305fSDimitry Andric return GPRegSet; 117d409305fSDimitry Andric if (reg_num >= k_first_fpr && reg_num <= k_last_fpr) 118d409305fSDimitry Andric return FPRegSet; 119d409305fSDimitry Andric break; 120d409305fSDimitry Andric default: 121d409305fSDimitry Andric llvm_unreachable("Unhandled target architecture."); 122d409305fSDimitry Andric } 123d409305fSDimitry Andric 124d409305fSDimitry Andric llvm_unreachable("Register does not belong to any register set"); 125d409305fSDimitry Andric } 126d409305fSDimitry Andric 127d409305fSDimitry Andric uint32_t NativeRegisterContextFreeBSD_powerpc::GetUserRegisterCount() const { 128d409305fSDimitry Andric uint32_t count = 0; 129d409305fSDimitry Andric for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) 130d409305fSDimitry Andric count += GetRegisterSet(set_index)->num_registers; 131d409305fSDimitry Andric return count; 132d409305fSDimitry Andric } 133d409305fSDimitry Andric 134d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet(RegSetKind set) { 135d409305fSDimitry Andric switch (set) { 136d409305fSDimitry Andric case GPRegSet: 137d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), 138d409305fSDimitry Andric m_reg_data.data()); 139d409305fSDimitry Andric case FPRegSet: 140d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), 141d409305fSDimitry Andric m_reg_data.data() + sizeof(reg)); 142d409305fSDimitry Andric } 143d409305fSDimitry Andric llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet"); 144d409305fSDimitry Andric } 145d409305fSDimitry Andric 146d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet(RegSetKind set) { 147d409305fSDimitry Andric switch (set) { 148d409305fSDimitry Andric case GPRegSet: 149d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), 150d409305fSDimitry Andric m_reg_data.data()); 151d409305fSDimitry Andric case FPRegSet: 152d409305fSDimitry Andric return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), 153d409305fSDimitry Andric m_reg_data.data() + sizeof(reg)); 154d409305fSDimitry Andric } 155d409305fSDimitry Andric llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet"); 156d409305fSDimitry Andric } 157d409305fSDimitry Andric 158d409305fSDimitry Andric Status 159d409305fSDimitry Andric NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info, 160d409305fSDimitry Andric RegisterValue ®_value) { 161d409305fSDimitry Andric Status error; 162d409305fSDimitry Andric 163d409305fSDimitry Andric if (!reg_info) { 164d409305fSDimitry Andric error.SetErrorString("reg_info NULL"); 165d409305fSDimitry Andric return error; 166d409305fSDimitry Andric } 167d409305fSDimitry Andric 168d409305fSDimitry Andric const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 169d409305fSDimitry Andric 170d409305fSDimitry Andric if (reg == LLDB_INVALID_REGNUM) 171d409305fSDimitry Andric return Status("no lldb regnum for %s", reg_info && reg_info->name 172d409305fSDimitry Andric ? reg_info->name 173d409305fSDimitry Andric : "<unknown register>"); 174d409305fSDimitry Andric 175bdd1243dSDimitry Andric std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); 176d409305fSDimitry Andric if (!opt_set) { 177d409305fSDimitry Andric // This is likely an internal register for lldb use only and should not be 178d409305fSDimitry Andric // directly queried. 179d409305fSDimitry Andric error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 180d409305fSDimitry Andric reg_info->name); 181d409305fSDimitry Andric return error; 182d409305fSDimitry Andric } 183d409305fSDimitry Andric 1841ac55f4cSDimitry Andric RegSetKind set = *opt_set; 185d409305fSDimitry Andric error = ReadRegisterSet(set); 186d409305fSDimitry Andric if (error.Fail()) 187d409305fSDimitry Andric return error; 188d409305fSDimitry Andric 189d409305fSDimitry Andric assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 190d409305fSDimitry Andric reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, 191d409305fSDimitry Andric reg_info->byte_size, endian::InlHostByteOrder()); 192d409305fSDimitry Andric return error; 193d409305fSDimitry Andric } 194d409305fSDimitry Andric 195d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_powerpc::WriteRegister( 196d409305fSDimitry Andric const RegisterInfo *reg_info, const RegisterValue ®_value) { 197d409305fSDimitry Andric Status error; 198d409305fSDimitry Andric 199d409305fSDimitry Andric if (!reg_info) 200d409305fSDimitry Andric return Status("reg_info NULL"); 201d409305fSDimitry Andric 202d409305fSDimitry Andric const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 203d409305fSDimitry Andric 204d409305fSDimitry Andric if (reg == LLDB_INVALID_REGNUM) 205d409305fSDimitry Andric return Status("no lldb regnum for %s", reg_info && reg_info->name 206d409305fSDimitry Andric ? reg_info->name 207d409305fSDimitry Andric : "<unknown register>"); 208d409305fSDimitry Andric 209bdd1243dSDimitry Andric std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg); 210d409305fSDimitry Andric if (!opt_set) { 211d409305fSDimitry Andric // This is likely an internal register for lldb use only and should not be 212d409305fSDimitry Andric // directly queried. 213d409305fSDimitry Andric error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", 214d409305fSDimitry Andric reg_info->name); 215d409305fSDimitry Andric return error; 216d409305fSDimitry Andric } 217d409305fSDimitry Andric 2181ac55f4cSDimitry Andric RegSetKind set = *opt_set; 219d409305fSDimitry Andric error = ReadRegisterSet(set); 220d409305fSDimitry Andric if (error.Fail()) 221d409305fSDimitry Andric return error; 222d409305fSDimitry Andric 223d409305fSDimitry Andric assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); 224d409305fSDimitry Andric ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), 225d409305fSDimitry Andric reg_info->byte_size); 226d409305fSDimitry Andric 227d409305fSDimitry Andric return WriteRegisterSet(set); 228d409305fSDimitry Andric } 229d409305fSDimitry Andric 230d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_powerpc::ReadAllRegisterValues( 23181ad6265SDimitry Andric lldb::WritableDataBufferSP &data_sp) { 232d409305fSDimitry Andric Status error; 233d409305fSDimitry Andric 234d409305fSDimitry Andric error = ReadRegisterSet(GPRegSet); 235d409305fSDimitry Andric if (error.Fail()) 236d409305fSDimitry Andric return error; 237d409305fSDimitry Andric 238d409305fSDimitry Andric error = ReadRegisterSet(FPRegSet); 239d409305fSDimitry Andric if (error.Fail()) 240d409305fSDimitry Andric return error; 241d409305fSDimitry Andric 242d409305fSDimitry Andric data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); 243d409305fSDimitry Andric uint8_t *dst = data_sp->GetBytes(); 244d409305fSDimitry Andric ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); 245d409305fSDimitry Andric 246d409305fSDimitry Andric return error; 247d409305fSDimitry Andric } 248d409305fSDimitry Andric 249d409305fSDimitry Andric Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues( 250d409305fSDimitry Andric const lldb::DataBufferSP &data_sp) { 251d409305fSDimitry Andric Status error; 252d409305fSDimitry Andric 253d409305fSDimitry Andric if (!data_sp) { 254d409305fSDimitry Andric error.SetErrorStringWithFormat( 255d409305fSDimitry Andric "NativeRegisterContextFreeBSD_powerpc::%s invalid data_sp provided", 256d409305fSDimitry Andric __FUNCTION__); 257d409305fSDimitry Andric return error; 258d409305fSDimitry Andric } 259d409305fSDimitry Andric 260d409305fSDimitry Andric if (data_sp->GetByteSize() != m_reg_data.size()) { 261d409305fSDimitry Andric error.SetErrorStringWithFormat( 262d409305fSDimitry Andric "NativeRegisterContextFreeBSD_powerpc::%s data_sp contained mismatched " 263d409305fSDimitry Andric "data size, expected %zu, actual %" PRIu64, 264d409305fSDimitry Andric __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); 265d409305fSDimitry Andric return error; 266d409305fSDimitry Andric } 267d409305fSDimitry Andric 26881ad6265SDimitry Andric const uint8_t *src = data_sp->GetBytes(); 269d409305fSDimitry Andric if (src == nullptr) { 270d409305fSDimitry Andric error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s " 271d409305fSDimitry Andric "DataBuffer::GetBytes() returned a null " 272d409305fSDimitry Andric "pointer", 273d409305fSDimitry Andric __FUNCTION__); 274d409305fSDimitry Andric return error; 275d409305fSDimitry Andric } 276d409305fSDimitry Andric ::memcpy(m_reg_data.data(), src, m_reg_data.size()); 277d409305fSDimitry Andric 278d409305fSDimitry Andric error = WriteRegisterSet(GPRegSet); 279d409305fSDimitry Andric if (error.Fail()) 280d409305fSDimitry Andric return error; 281d409305fSDimitry Andric 282d409305fSDimitry Andric return WriteRegisterSet(FPRegSet); 283d409305fSDimitry Andric } 284d409305fSDimitry Andric 285d409305fSDimitry Andric llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom( 286d409305fSDimitry Andric NativeRegisterContextFreeBSD &source) { 287d409305fSDimitry Andric return llvm::Error::success(); 288d409305fSDimitry Andric } 289d409305fSDimitry Andric 290d409305fSDimitry Andric #endif // defined (__powerpc__) 291