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