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