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