xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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 *
CreateHostNativeRegisterContextFreeBSD(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 *
CreateRegisterInfoInterface(const ArchSpec & target_arch)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 
NativeRegisterContextFreeBSD_powerpc(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)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 &
GetRegisterInfo() const91 NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
92   return static_cast<RegisterContextFreeBSD_powerpc &>(
93       *m_register_info_interface_up);
94 }
95 
GetRegisterSetCount() const96 uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const {
97   return k_num_register_sets;
98 }
99 
100 const RegisterSet *
GetRegisterSet(uint32_t set_index) const101 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>
GetSetForNativeRegNum(uint32_t reg_num) const111 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 
GetUserRegisterCount() const127 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 
ReadRegisterSet(RegSetKind set)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 
WriteRegisterSet(RegSetKind set)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
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)159 NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info,
160                                                    RegisterValue &reg_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 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)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("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 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)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 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)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 
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD & source)285 llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom(
286     NativeRegisterContextFreeBSD &source) {
287   return llvm::Error::success();
288 }
289 
290 #endif // defined (__powerpc__)
291