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