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 *
CreateHostNativeRegisterContextFreeBSD(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 *
CreateRegisterInfoInterface(const ArchSpec & target_arch)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
NativeRegisterContextFreeBSD_powerpc(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 &
GetRegisterInfo() const90 NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
91 return static_cast<RegisterContextFreeBSD_powerpc &>(
92 *m_register_info_interface_up);
93 }
94
GetRegisterSetCount() const95 uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const {
96 return k_num_register_sets;
97 }
98
99 const RegisterSet *
GetRegisterSet(uint32_t set_index) const100 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>
GetSetForNativeRegNum(uint32_t reg_num) const110 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
GetUserRegisterCount() const126 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
ReadRegisterSet(RegSetKind set)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
WriteRegisterSet(RegSetKind set)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
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)158 NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info,
159 RegisterValue ®_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
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)194 Status NativeRegisterContextFreeBSD_powerpc::WriteRegister(
195 const RegisterInfo *reg_info, const RegisterValue ®_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
ReadAllRegisterValues(lldb::DataBufferSP & data_sp)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
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)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
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD & source)284 llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom(
285 NativeRegisterContextFreeBSD &source) {
286 return llvm::Error::success();
287 }
288
289 #endif // defined (__powerpc__)
290