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 &reg_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 &reg_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