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, NativeThreadProtocol &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, NativeThreadProtocol &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 ®_value) { |
161 | Status error; |
162 | |
163 | if (!reg_info) { |
164 | error.SetErrorString("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("no lldb regnum for %s" , reg_info && reg_info->name |
172 | ? reg_info->name |
173 | : "<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.SetErrorStringWithFormat("register \"%s\" is in unrecognized set" , |
180 | 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 ®_value) { |
197 | Status error; |
198 | |
199 | if (!reg_info) |
200 | return Status("reg_info NULL" ); |
201 | |
202 | const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; |
203 | |
204 | if (reg == LLDB_INVALID_REGNUM) |
205 | return Status("no lldb regnum for %s" , reg_info && reg_info->name |
206 | ? reg_info->name |
207 | : "<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.SetErrorStringWithFormat("register \"%s\" is in unrecognized set" , |
214 | 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.SetErrorStringWithFormat( |
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.SetErrorStringWithFormat( |
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.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s " |
271 | "DataBuffer::GetBytes() returned a null " |
272 | "pointer" , |
273 | __FUNCTION__); |
274 | return error; |
275 | } |
276 | ::memcpy(m_reg_data.data(), src, m_reg_data.size()); |
277 | |
278 | error = WriteRegisterSet(GPRegSet); |
279 | if (error.Fail()) |
280 | return error; |
281 | |
282 | return WriteRegisterSet(FPRegSet); |
283 | } |
284 | |
285 | llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom( |
286 | NativeRegisterContextFreeBSD &source) { |
287 | return llvm::Error::success(); |
288 | } |
289 | |
290 | #endif // defined (__powerpc__) |
291 | |