xref: /llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp (revision 0642cd768b80665585c8500bed2933a3b99123dc)
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 
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace lldb_private::process_freebsd;
32 
33 static 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 
46 static 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.
59 enum { k_num_register_sets = 2 };
60 
61 static 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 
68 NativeRegisterContextFreeBSD *
69 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
70     const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
71   return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread);
72 }
73 
74 static RegisterInfoInterface *
75 CreateRegisterInfoInterface(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 
85 NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc(
86     const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread)
87     : NativeRegisterContextRegisterInfo(
88           native_thread, CreateRegisterInfoInterface(target_arch)) {}
89 
90 RegisterContextFreeBSD_powerpc &
91 NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
92   return static_cast<RegisterContextFreeBSD_powerpc &>(
93       *m_register_info_interface_up);
94 }
95 
96 uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const {
97   return k_num_register_sets;
98 }
99 
100 const RegisterSet *
101 NativeRegisterContextFreeBSD_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 
110 std::optional<NativeRegisterContextFreeBSD_powerpc::RegSetKind>
111 NativeRegisterContextFreeBSD_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 
127 uint32_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 
134 Status 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 
146 Status 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 
158 Status
159 NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info,
160                                                    RegisterValue &reg_value) {
161   Status error;
162 
163   if (!reg_info) {
164     error = Status::FromErrorString("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::FromErrorStringWithFormat(
172         "no lldb regnum for %s",
173         reg_info && reg_info->name ? reg_info->name : "<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 = Status::FromErrorStringWithFormat(
180         "register \"%s\" is in unrecognized set", 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 
195 Status NativeRegisterContextFreeBSD_powerpc::WriteRegister(
196     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
197   Status error;
198 
199   if (!reg_info)
200     return Status::FromErrorString("reg_info NULL");
201 
202   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
203 
204   if (reg == LLDB_INVALID_REGNUM)
205     return Status::FromErrorStringWithFormat(
206         "no lldb regnum for %s",
207         reg_info && reg_info->name ? reg_info->name : "<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 = Status::FromErrorStringWithFormat(
214         "register \"%s\" is in unrecognized set", 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 
230 Status 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 
249 Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues(
250     const lldb::DataBufferSP &data_sp) {
251   Status error;
252 
253   if (!data_sp) {
254     error = Status::FromErrorStringWithFormat(
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 = Status::FromErrorStringWithFormat(
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 = Status::FromErrorStringWithFormat(
271         "NativeRegisterContextFreeBSD_powerpc::%s "
272         "DataBuffer::GetBytes() returned a null "
273         "pointer",
274         __FUNCTION__);
275     return error;
276   }
277   ::memcpy(m_reg_data.data(), src, m_reg_data.size());
278 
279   error = WriteRegisterSet(GPRegSet);
280   if (error.Fail())
281     return error;
282 
283   return WriteRegisterSet(FPRegSet);
284 }
285 
286 llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom(
287     NativeRegisterContextFreeBSD &source) {
288   return llvm::Error::success();
289 }
290 
291 #endif // defined (__powerpc__)
292