1aae0a752SEugene Zemtsov //===-- NativeRegisterContextLinux_ppc64le.cpp ------------------*- C++ -*-===//
2aae0a752SEugene Zemtsov //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6aae0a752SEugene Zemtsov //
7aae0a752SEugene Zemtsov //===----------------------------------------------------------------------===//
8aae0a752SEugene Zemtsov 
9aae0a752SEugene Zemtsov // This implementation is related to the OpenPOWER ABI for Power Architecture
10aae0a752SEugene Zemtsov // 64-bit ELF V2 ABI
11aae0a752SEugene Zemtsov 
12aae0a752SEugene Zemtsov #if defined(__powerpc64__)
13aae0a752SEugene Zemtsov 
14aae0a752SEugene Zemtsov #include "NativeRegisterContextLinux_ppc64le.h"
15aae0a752SEugene Zemtsov 
16aae0a752SEugene Zemtsov #include "lldb/Host/common/NativeProcessProtocol.h"
17aae0a752SEugene Zemtsov #include "lldb/Utility/DataBufferHeap.h"
18aae0a752SEugene Zemtsov #include "lldb/Utility/Log.h"
19d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
20aae0a752SEugene Zemtsov #include "lldb/Utility/Status.h"
21aae0a752SEugene Zemtsov 
22aae0a752SEugene Zemtsov #include "Plugins/Process/Linux/NativeProcessLinux.h"
23aae0a752SEugene Zemtsov #include "Plugins/Process/Linux/Procfs.h"
24aae0a752SEugene Zemtsov #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
25aae0a752SEugene Zemtsov #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
26aae0a752SEugene Zemtsov 
27aae0a752SEugene Zemtsov // System includes - They have to be included after framework includes because
2805097246SAdrian Prantl // they define some macros which collide with variable names in other modules
29aae0a752SEugene Zemtsov #include <sys/socket.h>
30aae0a752SEugene Zemtsov #include <elf.h>
31aae0a752SEugene Zemtsov #include <asm/ptrace.h>
32aae0a752SEugene Zemtsov 
33e6a66105SPavel Labath #define REG_CONTEXT_SIZE                                                       \
34e6a66105SPavel Labath   (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le))
35aae0a752SEugene Zemtsov using namespace lldb;
36aae0a752SEugene Zemtsov using namespace lldb_private;
37aae0a752SEugene Zemtsov using namespace lldb_private::process_linux;
38aae0a752SEugene Zemtsov 
39aae0a752SEugene Zemtsov static const uint32_t g_gpr_regnums_ppc64le[] = {
40aae0a752SEugene Zemtsov     gpr_r0_ppc64le,   gpr_r1_ppc64le,  gpr_r2_ppc64le,     gpr_r3_ppc64le,
41aae0a752SEugene Zemtsov     gpr_r4_ppc64le,   gpr_r5_ppc64le,  gpr_r6_ppc64le,     gpr_r7_ppc64le,
42aae0a752SEugene Zemtsov     gpr_r8_ppc64le,   gpr_r9_ppc64le,  gpr_r10_ppc64le,    gpr_r11_ppc64le,
43aae0a752SEugene Zemtsov     gpr_r12_ppc64le,  gpr_r13_ppc64le, gpr_r14_ppc64le,    gpr_r15_ppc64le,
44aae0a752SEugene Zemtsov     gpr_r16_ppc64le,  gpr_r17_ppc64le, gpr_r18_ppc64le,    gpr_r19_ppc64le,
45aae0a752SEugene Zemtsov     gpr_r20_ppc64le,  gpr_r21_ppc64le, gpr_r22_ppc64le,    gpr_r23_ppc64le,
46aae0a752SEugene Zemtsov     gpr_r24_ppc64le,  gpr_r25_ppc64le, gpr_r26_ppc64le,    gpr_r27_ppc64le,
47aae0a752SEugene Zemtsov     gpr_r28_ppc64le,  gpr_r29_ppc64le, gpr_r30_ppc64le,    gpr_r31_ppc64le,
48aae0a752SEugene Zemtsov     gpr_pc_ppc64le,   gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
49aae0a752SEugene Zemtsov     gpr_lr_ppc64le,   gpr_xer_ppc64le, gpr_cr_ppc64le,     gpr_softe_ppc64le,
50aae0a752SEugene Zemtsov     gpr_trap_ppc64le,
515e5dd706SPavel Labath     LLDB_INVALID_REGNUM // register sets need to end with this flag
52aae0a752SEugene Zemtsov };
53aae0a752SEugene Zemtsov 
54e6a66105SPavel Labath static const uint32_t g_fpr_regnums_ppc64le[] = {
55e6a66105SPavel Labath     fpr_f0_ppc64le,    fpr_f1_ppc64le,  fpr_f2_ppc64le,  fpr_f3_ppc64le,
56e6a66105SPavel Labath     fpr_f4_ppc64le,    fpr_f5_ppc64le,  fpr_f6_ppc64le,  fpr_f7_ppc64le,
57e6a66105SPavel Labath     fpr_f8_ppc64le,    fpr_f9_ppc64le,  fpr_f10_ppc64le, fpr_f11_ppc64le,
58e6a66105SPavel Labath     fpr_f12_ppc64le,   fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le,
59e6a66105SPavel Labath     fpr_f16_ppc64le,   fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le,
60e6a66105SPavel Labath     fpr_f20_ppc64le,   fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le,
61e6a66105SPavel Labath     fpr_f24_ppc64le,   fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le,
62e6a66105SPavel Labath     fpr_f28_ppc64le,   fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le,
63e6a66105SPavel Labath     fpr_fpscr_ppc64le,
645e5dd706SPavel Labath     LLDB_INVALID_REGNUM // register sets need to end with this flag
65e6a66105SPavel Labath };
66e6a66105SPavel Labath 
67e6a66105SPavel Labath static const uint32_t g_vmx_regnums_ppc64le[] = {
68e6a66105SPavel Labath     vmx_vr0_ppc64le,  vmx_vr1_ppc64le,    vmx_vr2_ppc64le,  vmx_vr3_ppc64le,
69e6a66105SPavel Labath     vmx_vr4_ppc64le,  vmx_vr5_ppc64le,    vmx_vr6_ppc64le,  vmx_vr7_ppc64le,
70e6a66105SPavel Labath     vmx_vr8_ppc64le,  vmx_vr9_ppc64le,    vmx_vr10_ppc64le, vmx_vr11_ppc64le,
71e6a66105SPavel Labath     vmx_vr12_ppc64le, vmx_vr13_ppc64le,   vmx_vr14_ppc64le, vmx_vr15_ppc64le,
72e6a66105SPavel Labath     vmx_vr16_ppc64le, vmx_vr17_ppc64le,   vmx_vr18_ppc64le, vmx_vr19_ppc64le,
73e6a66105SPavel Labath     vmx_vr20_ppc64le, vmx_vr21_ppc64le,   vmx_vr22_ppc64le, vmx_vr23_ppc64le,
74e6a66105SPavel Labath     vmx_vr24_ppc64le, vmx_vr25_ppc64le,   vmx_vr26_ppc64le, vmx_vr27_ppc64le,
75e6a66105SPavel Labath     vmx_vr28_ppc64le, vmx_vr29_ppc64le,   vmx_vr30_ppc64le, vmx_vr31_ppc64le,
76e6a66105SPavel Labath     vmx_vscr_ppc64le, vmx_vrsave_ppc64le,
775e5dd706SPavel Labath     LLDB_INVALID_REGNUM // register sets need to end with this flag
78e6a66105SPavel Labath };
79e6a66105SPavel Labath 
80e6a66105SPavel Labath static const uint32_t g_vsx_regnums_ppc64le[] = {
81e6a66105SPavel Labath     vsx_vs0_ppc64le,  vsx_vs1_ppc64le,  vsx_vs2_ppc64le,  vsx_vs3_ppc64le,
82e6a66105SPavel Labath     vsx_vs4_ppc64le,  vsx_vs5_ppc64le,  vsx_vs6_ppc64le,  vsx_vs7_ppc64le,
83e6a66105SPavel Labath     vsx_vs8_ppc64le,  vsx_vs9_ppc64le,  vsx_vs10_ppc64le, vsx_vs11_ppc64le,
84e6a66105SPavel Labath     vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le,
85e6a66105SPavel Labath     vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le,
86e6a66105SPavel Labath     vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le,
87e6a66105SPavel Labath     vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le,
88e6a66105SPavel Labath     vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le,
89e6a66105SPavel Labath     vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le,
90e6a66105SPavel Labath     vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le,
91e6a66105SPavel Labath     vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le,
92e6a66105SPavel Labath     vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le,
93e6a66105SPavel Labath     vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le,
94e6a66105SPavel Labath     vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le,
95e6a66105SPavel Labath     vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le,
96e6a66105SPavel Labath     vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le,
975e5dd706SPavel Labath     LLDB_INVALID_REGNUM // register sets need to end with this flag
98e6a66105SPavel Labath };
99e6a66105SPavel Labath 
100aae0a752SEugene Zemtsov namespace {
101aae0a752SEugene Zemtsov // Number of register sets provided by this context.
102e6a66105SPavel Labath enum { k_num_register_sets = 4 };
103aae0a752SEugene Zemtsov }
104aae0a752SEugene Zemtsov 
105aae0a752SEugene Zemtsov static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
106aae0a752SEugene Zemtsov     {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
107aae0a752SEugene Zemtsov      g_gpr_regnums_ppc64le},
108e6a66105SPavel Labath     {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le,
109e6a66105SPavel Labath      g_fpr_regnums_ppc64le},
110e6a66105SPavel Labath     {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le,
111e6a66105SPavel Labath      g_vmx_regnums_ppc64le},
112e6a66105SPavel Labath     {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le,
113e6a66105SPavel Labath      g_vsx_regnums_ppc64le},
114aae0a752SEugene Zemtsov };
115aae0a752SEugene Zemtsov 
116d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux>
117aae0a752SEugene Zemtsov NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
118d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
119aae0a752SEugene Zemtsov   switch (target_arch.GetMachine()) {
120aae0a752SEugene Zemtsov   case llvm::Triple::ppc64le:
121d37349f3SPavel Labath     return llvm::make_unique<NativeRegisterContextLinux_ppc64le>(target_arch,
122d37349f3SPavel Labath                                                                  native_thread);
123aae0a752SEugene Zemtsov   default:
124aae0a752SEugene Zemtsov     llvm_unreachable("have no register context for architecture");
125aae0a752SEugene Zemtsov   }
126aae0a752SEugene Zemtsov }
127aae0a752SEugene Zemtsov 
128aae0a752SEugene Zemtsov NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
129d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
130d37349f3SPavel Labath     : NativeRegisterContextLinux(native_thread,
131aae0a752SEugene Zemtsov                                  new RegisterInfoPOSIX_ppc64le(target_arch)) {
132aae0a752SEugene Zemtsov   if (target_arch.GetMachine() != llvm::Triple::ppc64le) {
133aae0a752SEugene Zemtsov     llvm_unreachable("Unhandled target architecture.");
134aae0a752SEugene Zemtsov   }
135aae0a752SEugene Zemtsov 
136aae0a752SEugene Zemtsov   ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
137e6a66105SPavel Labath   ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le));
138e6a66105SPavel Labath   ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le));
139e6a66105SPavel Labath   ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le));
140c51ad483SPavel Labath   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
141aae0a752SEugene Zemtsov }
142aae0a752SEugene Zemtsov 
143aae0a752SEugene Zemtsov uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
144aae0a752SEugene Zemtsov   return k_num_register_sets;
145aae0a752SEugene Zemtsov }
146aae0a752SEugene Zemtsov 
147aae0a752SEugene Zemtsov const RegisterSet *
148aae0a752SEugene Zemtsov NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
149aae0a752SEugene Zemtsov   if (set_index < k_num_register_sets)
150aae0a752SEugene Zemtsov     return &g_reg_sets_ppc64le[set_index];
151aae0a752SEugene Zemtsov 
152aae0a752SEugene Zemtsov   return nullptr;
153aae0a752SEugene Zemtsov }
154aae0a752SEugene Zemtsov 
155aae0a752SEugene Zemtsov uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
156aae0a752SEugene Zemtsov   uint32_t count = 0;
157aae0a752SEugene Zemtsov   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
158aae0a752SEugene Zemtsov     count += g_reg_sets_ppc64le[set_index].num_registers;
159aae0a752SEugene Zemtsov   return count;
160aae0a752SEugene Zemtsov }
161aae0a752SEugene Zemtsov 
162aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::ReadRegister(
163aae0a752SEugene Zemtsov     const RegisterInfo *reg_info, RegisterValue &reg_value) {
164aae0a752SEugene Zemtsov   Status error;
165aae0a752SEugene Zemtsov 
166aae0a752SEugene Zemtsov   if (!reg_info) {
167aae0a752SEugene Zemtsov     error.SetErrorString("reg_info NULL");
168aae0a752SEugene Zemtsov     return error;
169aae0a752SEugene Zemtsov   }
170aae0a752SEugene Zemtsov 
171aae0a752SEugene Zemtsov   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
172aae0a752SEugene Zemtsov 
173e6a66105SPavel Labath   if (IsFPR(reg)) {
174e6a66105SPavel Labath     error = ReadFPR();
175e6a66105SPavel Labath     if (error.Fail())
176e6a66105SPavel Labath       return error;
177e6a66105SPavel Labath 
178e6a66105SPavel Labath     // Get pointer to m_fpr_ppc64le variable and set the data from it.
179e6a66105SPavel Labath     uint32_t fpr_offset = CalculateFprOffset(reg_info);
180e6a66105SPavel Labath     assert(fpr_offset < sizeof m_fpr_ppc64le);
181e6a66105SPavel Labath     uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
182e6a66105SPavel Labath     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
183e6a66105SPavel Labath                                 eByteOrderLittle, error);
184e6a66105SPavel Labath   } else if (IsVSX(reg)) {
185e6a66105SPavel Labath     uint32_t vsx_offset = CalculateVsxOffset(reg_info);
186e6a66105SPavel Labath     assert(vsx_offset < sizeof(m_vsx_ppc64le));
187e6a66105SPavel Labath 
188e6a66105SPavel Labath     if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
189e6a66105SPavel Labath       error = ReadVSX();
190e6a66105SPavel Labath       if (error.Fail())
191e6a66105SPavel Labath         return error;
192e6a66105SPavel Labath 
193e6a66105SPavel Labath       error = ReadFPR();
194e6a66105SPavel Labath       if (error.Fail())
195e6a66105SPavel Labath         return error;
196e6a66105SPavel Labath 
197e6a66105SPavel Labath       uint64_t value[2];
198e6a66105SPavel Labath       uint8_t *dst, *src;
199e6a66105SPavel Labath       dst = (uint8_t *)&value;
200e6a66105SPavel Labath       src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
201e6a66105SPavel Labath       ::memcpy(dst, src, 8);
202e6a66105SPavel Labath       dst += 8;
203e6a66105SPavel Labath       src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
204e6a66105SPavel Labath       ::memcpy(dst, src, 8);
205e6a66105SPavel Labath       reg_value.SetFromMemoryData(reg_info, &value, reg_info->byte_size,
206e6a66105SPavel Labath                                   eByteOrderLittle, error);
207e6a66105SPavel Labath     } else {
208e6a66105SPavel Labath       error = ReadVMX();
209e6a66105SPavel Labath       if (error.Fail())
210e6a66105SPavel Labath         return error;
211e6a66105SPavel Labath 
212e6a66105SPavel Labath       // Get pointer to m_vmx_ppc64le variable and set the data from it.
213e6a66105SPavel Labath       uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
214e6a66105SPavel Labath       uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
215e6a66105SPavel Labath       reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
216e6a66105SPavel Labath                                   eByteOrderLittle, error);
217e6a66105SPavel Labath     }
218e6a66105SPavel Labath   } else if (IsVMX(reg)) {
219e6a66105SPavel Labath     error = ReadVMX();
220e6a66105SPavel Labath     if (error.Fail())
221e6a66105SPavel Labath       return error;
222e6a66105SPavel Labath 
223e6a66105SPavel Labath     // Get pointer to m_vmx_ppc64le variable and set the data from it.
224e6a66105SPavel Labath     uint32_t vmx_offset = CalculateVmxOffset(reg_info);
225e6a66105SPavel Labath     assert(vmx_offset < sizeof m_vmx_ppc64le);
226e6a66105SPavel Labath     uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
227e6a66105SPavel Labath     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
228e6a66105SPavel Labath                                 eByteOrderLittle, error);
229e6a66105SPavel Labath   } else if (IsGPR(reg)) {
230aae0a752SEugene Zemtsov     error = ReadGPR();
231aae0a752SEugene Zemtsov     if (error.Fail())
232aae0a752SEugene Zemtsov       return error;
233aae0a752SEugene Zemtsov 
234aae0a752SEugene Zemtsov     uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
235aae0a752SEugene Zemtsov     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
236aae0a752SEugene Zemtsov                                 eByteOrderLittle, error);
237aae0a752SEugene Zemtsov   } else {
238e6a66105SPavel Labath     return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
239e6a66105SPavel Labath                   "or VMX, read strategy unknown");
240aae0a752SEugene Zemtsov   }
241aae0a752SEugene Zemtsov 
242aae0a752SEugene Zemtsov   return error;
243aae0a752SEugene Zemtsov }
244aae0a752SEugene Zemtsov 
245aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::WriteRegister(
246aae0a752SEugene Zemtsov     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
247aae0a752SEugene Zemtsov   Status error;
248aae0a752SEugene Zemtsov   if (!reg_info)
249aae0a752SEugene Zemtsov     return Status("reg_info NULL");
250aae0a752SEugene Zemtsov 
251aae0a752SEugene Zemtsov   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
252aae0a752SEugene Zemtsov   if (reg_index == LLDB_INVALID_REGNUM)
253aae0a752SEugene Zemtsov     return Status("no lldb regnum for %s", reg_info && reg_info->name
254aae0a752SEugene Zemtsov                                                ? reg_info->name
255aae0a752SEugene Zemtsov                                                : "<unknown register>");
256aae0a752SEugene Zemtsov 
257aae0a752SEugene Zemtsov   if (IsGPR(reg_index)) {
258aae0a752SEugene Zemtsov     error = ReadGPR();
259aae0a752SEugene Zemtsov     if (error.Fail())
260aae0a752SEugene Zemtsov       return error;
261aae0a752SEugene Zemtsov 
262aae0a752SEugene Zemtsov     uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset;
263aae0a752SEugene Zemtsov     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
264aae0a752SEugene Zemtsov 
265aae0a752SEugene Zemtsov     error = WriteGPR();
266aae0a752SEugene Zemtsov     if (error.Fail())
267aae0a752SEugene Zemtsov       return error;
268aae0a752SEugene Zemtsov 
269aae0a752SEugene Zemtsov     return Status();
270aae0a752SEugene Zemtsov   }
271aae0a752SEugene Zemtsov 
272e6a66105SPavel Labath   if (IsFPR(reg_index)) {
273e6a66105SPavel Labath     error = ReadFPR();
274e6a66105SPavel Labath     if (error.Fail())
275e6a66105SPavel Labath       return error;
276e6a66105SPavel Labath 
277e6a66105SPavel Labath     // Get pointer to m_fpr_ppc64le variable and set the data to it.
278e6a66105SPavel Labath     uint32_t fpr_offset = CalculateFprOffset(reg_info);
279e6a66105SPavel Labath     assert(fpr_offset < GetFPRSize());
280e6a66105SPavel Labath     uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
281e6a66105SPavel Labath     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
282e6a66105SPavel Labath 
283e6a66105SPavel Labath     error = WriteFPR();
284e6a66105SPavel Labath     if (error.Fail())
285e6a66105SPavel Labath       return error;
286e6a66105SPavel Labath 
287e6a66105SPavel Labath     return Status();
288e6a66105SPavel Labath   }
289e6a66105SPavel Labath 
290e6a66105SPavel Labath   if (IsVMX(reg_index)) {
291e6a66105SPavel Labath     error = ReadVMX();
292e6a66105SPavel Labath     if (error.Fail())
293e6a66105SPavel Labath       return error;
294e6a66105SPavel Labath 
295e6a66105SPavel Labath     // Get pointer to m_vmx_ppc64le variable and set the data to it.
296e6a66105SPavel Labath     uint32_t vmx_offset = CalculateVmxOffset(reg_info);
297e6a66105SPavel Labath     assert(vmx_offset < sizeof(m_vmx_ppc64le));
298e6a66105SPavel Labath     uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
299e6a66105SPavel Labath     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
300e6a66105SPavel Labath 
301e6a66105SPavel Labath     error = WriteVMX();
302e6a66105SPavel Labath     if (error.Fail())
303e6a66105SPavel Labath       return error;
304e6a66105SPavel Labath 
305e6a66105SPavel Labath     return Status();
306e6a66105SPavel Labath   }
307e6a66105SPavel Labath 
308e6a66105SPavel Labath   if (IsVSX(reg_index)) {
309e6a66105SPavel Labath     uint32_t vsx_offset = CalculateVsxOffset(reg_info);
310e6a66105SPavel Labath     assert(vsx_offset < sizeof(m_vsx_ppc64le));
311e6a66105SPavel Labath 
312e6a66105SPavel Labath     if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
313e6a66105SPavel Labath       error = ReadVSX();
314e6a66105SPavel Labath       if (error.Fail())
315e6a66105SPavel Labath         return error;
316e6a66105SPavel Labath 
317e6a66105SPavel Labath       error = ReadFPR();
318e6a66105SPavel Labath       if (error.Fail())
319e6a66105SPavel Labath         return error;
320e6a66105SPavel Labath 
321e6a66105SPavel Labath       uint64_t value[2];
322e6a66105SPavel Labath       ::memcpy(value, reg_value.GetBytes(), 16);
323e6a66105SPavel Labath       uint8_t *dst, *src;
324e6a66105SPavel Labath       src = (uint8_t *)value;
325e6a66105SPavel Labath       dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
326e6a66105SPavel Labath       ::memcpy(dst, src, 8);
327e6a66105SPavel Labath       src += 8;
328e6a66105SPavel Labath       dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
329e6a66105SPavel Labath       ::memcpy(dst, src, 8);
330e6a66105SPavel Labath 
331e6a66105SPavel Labath       WriteVSX();
332e6a66105SPavel Labath       WriteFPR();
333e6a66105SPavel Labath     } else {
334e6a66105SPavel Labath       error = ReadVMX();
335e6a66105SPavel Labath       if (error.Fail())
336e6a66105SPavel Labath         return error;
337e6a66105SPavel Labath 
338e6a66105SPavel Labath       // Get pointer to m_vmx_ppc64le variable and set the data from it.
339e6a66105SPavel Labath       uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
340e6a66105SPavel Labath       uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
341e6a66105SPavel Labath       ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
342e6a66105SPavel Labath       WriteVMX();
343e6a66105SPavel Labath     }
344e6a66105SPavel Labath 
345e6a66105SPavel Labath     return Status();
346e6a66105SPavel Labath   }
347e6a66105SPavel Labath 
348e6a66105SPavel Labath   return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
349e6a66105SPavel Labath                 "or VMX, write strategy unknown");
350aae0a752SEugene Zemtsov }
351aae0a752SEugene Zemtsov 
352aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
353aae0a752SEugene Zemtsov     lldb::DataBufferSP &data_sp) {
354aae0a752SEugene Zemtsov   Status error;
355aae0a752SEugene Zemtsov 
356aae0a752SEugene Zemtsov   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
357aae0a752SEugene Zemtsov   if (!data_sp)
358aae0a752SEugene Zemtsov     return Status("failed to allocate DataBufferHeap instance of size %" PRIu64,
359aae0a752SEugene Zemtsov                   REG_CONTEXT_SIZE);
360aae0a752SEugene Zemtsov 
361aae0a752SEugene Zemtsov   error = ReadGPR();
362aae0a752SEugene Zemtsov   if (error.Fail())
363aae0a752SEugene Zemtsov     return error;
364aae0a752SEugene Zemtsov 
365e6a66105SPavel Labath   error = ReadFPR();
366e6a66105SPavel Labath   if (error.Fail())
367e6a66105SPavel Labath     return error;
368e6a66105SPavel Labath 
369e6a66105SPavel Labath   error = ReadVMX();
370e6a66105SPavel Labath   if (error.Fail())
371e6a66105SPavel Labath     return error;
372e6a66105SPavel Labath 
373e6a66105SPavel Labath   error = ReadVSX();
374e6a66105SPavel Labath   if (error.Fail())
375e6a66105SPavel Labath     return error;
376e6a66105SPavel Labath 
377aae0a752SEugene Zemtsov   uint8_t *dst = data_sp->GetBytes();
378aae0a752SEugene Zemtsov   if (dst == nullptr) {
379aae0a752SEugene Zemtsov     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
380aae0a752SEugene Zemtsov                                    " returned a null pointer",
381aae0a752SEugene Zemtsov                                    REG_CONTEXT_SIZE);
382aae0a752SEugene Zemtsov     return error;
383aae0a752SEugene Zemtsov   }
384aae0a752SEugene Zemtsov 
385aae0a752SEugene Zemtsov   ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
386e6a66105SPavel Labath   dst += GetGPRSize();
387e6a66105SPavel Labath   ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
388e6a66105SPavel Labath   dst += GetFPRSize();
389e6a66105SPavel Labath   ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le));
390e6a66105SPavel Labath   dst += sizeof(m_vmx_ppc64le);
391e6a66105SPavel Labath   ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le));
392aae0a752SEugene Zemtsov 
393aae0a752SEugene Zemtsov   return error;
394aae0a752SEugene Zemtsov }
395aae0a752SEugene Zemtsov 
396aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
397aae0a752SEugene Zemtsov     const lldb::DataBufferSP &data_sp) {
398aae0a752SEugene Zemtsov   Status error;
399aae0a752SEugene Zemtsov 
400aae0a752SEugene Zemtsov   if (!data_sp) {
401aae0a752SEugene Zemtsov     error.SetErrorStringWithFormat(
402aae0a752SEugene Zemtsov         "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
403aae0a752SEugene Zemtsov         __FUNCTION__);
404aae0a752SEugene Zemtsov     return error;
405aae0a752SEugene Zemtsov   }
406aae0a752SEugene Zemtsov 
407aae0a752SEugene Zemtsov   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
408aae0a752SEugene Zemtsov     error.SetErrorStringWithFormat(
409aae0a752SEugene Zemtsov         "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
410aae0a752SEugene Zemtsov         "data size, expected %" PRIu64 ", actual %" PRIu64,
411aae0a752SEugene Zemtsov         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
412aae0a752SEugene Zemtsov     return error;
413aae0a752SEugene Zemtsov   }
414aae0a752SEugene Zemtsov 
415aae0a752SEugene Zemtsov   uint8_t *src = data_sp->GetBytes();
416aae0a752SEugene Zemtsov   if (src == nullptr) {
417aae0a752SEugene Zemtsov     error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s "
418aae0a752SEugene Zemtsov                                    "DataBuffer::GetBytes() returned a null "
419aae0a752SEugene Zemtsov                                    "pointer",
420aae0a752SEugene Zemtsov                                    __FUNCTION__);
421aae0a752SEugene Zemtsov     return error;
422aae0a752SEugene Zemtsov   }
423aae0a752SEugene Zemtsov 
424aae0a752SEugene Zemtsov   ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
425aae0a752SEugene Zemtsov   error = WriteGPR();
426aae0a752SEugene Zemtsov 
427e6a66105SPavel Labath   if (error.Fail())
428e6a66105SPavel Labath     return error;
429e6a66105SPavel Labath 
430e6a66105SPavel Labath   src += GetGPRSize();
431e6a66105SPavel Labath   ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
432e6a66105SPavel Labath 
433e6a66105SPavel Labath   error = WriteFPR();
434e6a66105SPavel Labath   if (error.Fail())
435e6a66105SPavel Labath     return error;
436e6a66105SPavel Labath 
437e6a66105SPavel Labath   src += GetFPRSize();
438e6a66105SPavel Labath   ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
439e6a66105SPavel Labath 
440e6a66105SPavel Labath   error = WriteVMX();
441e6a66105SPavel Labath   if (error.Fail())
442e6a66105SPavel Labath     return error;
443e6a66105SPavel Labath 
444e6a66105SPavel Labath   src += sizeof(m_vmx_ppc64le);
445e6a66105SPavel Labath   ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
446e6a66105SPavel Labath   error = WriteVSX();
447e6a66105SPavel Labath 
448aae0a752SEugene Zemtsov   return error;
449aae0a752SEugene Zemtsov }
450aae0a752SEugene Zemtsov 
451aae0a752SEugene Zemtsov bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
452aae0a752SEugene Zemtsov   return reg <= k_last_gpr_ppc64le; // GPR's come first.
453aae0a752SEugene Zemtsov }
454aae0a752SEugene Zemtsov 
455e6a66105SPavel Labath bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
456e6a66105SPavel Labath   return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
457e6a66105SPavel Labath }
458e6a66105SPavel Labath 
459aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::DoReadGPR(
460aae0a752SEugene Zemtsov     void *buf, size_t buf_size) {
461aae0a752SEugene Zemtsov   int regset = NT_PRSTATUS;
462aae0a752SEugene Zemtsov   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
463aae0a752SEugene Zemtsov                                            &regset, buf, buf_size);
464aae0a752SEugene Zemtsov }
465aae0a752SEugene Zemtsov 
466aae0a752SEugene Zemtsov Status NativeRegisterContextLinux_ppc64le::DoWriteGPR(
467aae0a752SEugene Zemtsov     void *buf, size_t buf_size) {
468aae0a752SEugene Zemtsov   int regset = NT_PRSTATUS;
469aae0a752SEugene Zemtsov   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
470aae0a752SEugene Zemtsov                                            &regset, buf, buf_size);
471aae0a752SEugene Zemtsov }
472aae0a752SEugene Zemtsov 
473e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::DoReadFPR(void *buf,
474e6a66105SPavel Labath                                                      size_t buf_size) {
475e6a66105SPavel Labath   int regset = NT_FPREGSET;
476e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
477e6a66105SPavel Labath                                            &regset, buf, buf_size);
478e6a66105SPavel Labath }
479e6a66105SPavel Labath 
480e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::DoWriteFPR(void *buf,
481e6a66105SPavel Labath                                                       size_t buf_size) {
482e6a66105SPavel Labath   int regset = NT_FPREGSET;
483e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
484e6a66105SPavel Labath                                            &regset, buf, buf_size);
485e6a66105SPavel Labath }
486e6a66105SPavel Labath 
487e6a66105SPavel Labath uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
488e6a66105SPavel Labath     const RegisterInfo *reg_info) const {
489e6a66105SPavel Labath   return reg_info->byte_offset -
490e6a66105SPavel Labath          GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
491e6a66105SPavel Labath }
492e6a66105SPavel Labath 
493e6a66105SPavel Labath uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
494e6a66105SPavel Labath     const RegisterInfo *reg_info) const {
495e6a66105SPavel Labath   return reg_info->byte_offset -
496e6a66105SPavel Labath          GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
497e6a66105SPavel Labath }
498e6a66105SPavel Labath 
499e6a66105SPavel Labath uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
500e6a66105SPavel Labath     const RegisterInfo *reg_info) const {
501e6a66105SPavel Labath   return reg_info->byte_offset -
502e6a66105SPavel Labath          GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
503e6a66105SPavel Labath }
504e6a66105SPavel Labath 
505e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
506e6a66105SPavel Labath   int regset = NT_PPC_VMX;
507e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
508e6a66105SPavel Labath                                            &regset, &m_vmx_ppc64le,
509e6a66105SPavel Labath                                            sizeof(m_vmx_ppc64le));
510e6a66105SPavel Labath }
511e6a66105SPavel Labath 
512e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
513e6a66105SPavel Labath   int regset = NT_PPC_VMX;
514e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
515e6a66105SPavel Labath                                            &regset, &m_vmx_ppc64le,
516e6a66105SPavel Labath                                            sizeof(m_vmx_ppc64le));
517e6a66105SPavel Labath }
518e6a66105SPavel Labath 
519e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
520e6a66105SPavel Labath   int regset = NT_PPC_VSX;
521e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
522e6a66105SPavel Labath                                            &regset, &m_vsx_ppc64le,
523e6a66105SPavel Labath                                            sizeof(m_vsx_ppc64le));
524e6a66105SPavel Labath }
525e6a66105SPavel Labath 
526e6a66105SPavel Labath Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
527e6a66105SPavel Labath   int regset = NT_PPC_VSX;
528e6a66105SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
529e6a66105SPavel Labath                                            &regset, &m_vsx_ppc64le,
530e6a66105SPavel Labath                                            sizeof(m_vsx_ppc64le));
531e6a66105SPavel Labath }
532e6a66105SPavel Labath 
533e6a66105SPavel Labath bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
534e6a66105SPavel Labath   return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
535e6a66105SPavel Labath }
536e6a66105SPavel Labath 
537e6a66105SPavel Labath bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
538e6a66105SPavel Labath   return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
539e6a66105SPavel Labath }
540e6a66105SPavel Labath 
541c51ad483SPavel Labath uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
542c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
543c51ad483SPavel Labath 
544c51ad483SPavel Labath   // Read hardware breakpoint and watchpoint information.
545c51ad483SPavel Labath   Status error = ReadHardwareDebugInfo();
546c51ad483SPavel Labath 
547c51ad483SPavel Labath   if (error.Fail())
548c51ad483SPavel Labath     return 0;
549c51ad483SPavel Labath 
550c51ad483SPavel Labath   LLDB_LOG(log, "{0}", m_max_hwp_supported);
551c51ad483SPavel Labath   return m_max_hwp_supported;
552c51ad483SPavel Labath }
553c51ad483SPavel Labath 
554c51ad483SPavel Labath uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
555c51ad483SPavel Labath     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
556c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
557c51ad483SPavel Labath   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
558c51ad483SPavel Labath            watch_flags);
559c51ad483SPavel Labath 
560c51ad483SPavel Labath   // Read hardware breakpoint and watchpoint information.
561c51ad483SPavel Labath   Status error = ReadHardwareDebugInfo();
562c51ad483SPavel Labath 
563c51ad483SPavel Labath   if (error.Fail())
564c51ad483SPavel Labath     return LLDB_INVALID_INDEX32;
565c51ad483SPavel Labath 
566c51ad483SPavel Labath   uint32_t control_value = 0, wp_index = 0;
567c51ad483SPavel Labath   lldb::addr_t real_addr = addr;
568c51ad483SPavel Labath   uint32_t rw_mode = 0;
569c51ad483SPavel Labath 
57005097246SAdrian Prantl   // Check if we are setting watchpoint other than read/write/access Update
57105097246SAdrian Prantl   // watchpoint flag to match ppc64le write-read bit configuration.
572c51ad483SPavel Labath   switch (watch_flags) {
573c51ad483SPavel Labath   case eWatchpointKindWrite:
574c51ad483SPavel Labath     rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
575c51ad483SPavel Labath     watch_flags = 2;
576c51ad483SPavel Labath     break;
577c51ad483SPavel Labath   case eWatchpointKindRead:
578c51ad483SPavel Labath     rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
579c51ad483SPavel Labath     watch_flags = 1;
580c51ad483SPavel Labath     break;
581c51ad483SPavel Labath   case (eWatchpointKindRead | eWatchpointKindWrite):
582c51ad483SPavel Labath     rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
583c51ad483SPavel Labath     break;
584c51ad483SPavel Labath   default:
585c51ad483SPavel Labath     return LLDB_INVALID_INDEX32;
586c51ad483SPavel Labath   }
587c51ad483SPavel Labath 
588c51ad483SPavel Labath   // Check if size has a valid hardware watchpoint length.
589c51ad483SPavel Labath   if (size != 1 && size != 2 && size != 4 && size != 8)
590c51ad483SPavel Labath     return LLDB_INVALID_INDEX32;
591c51ad483SPavel Labath 
59205097246SAdrian Prantl   // Check 8-byte alignment for hardware watchpoint target address. Below is a
59305097246SAdrian Prantl   // hack to recalculate address and size in order to make sure we can watch
59405097246SAdrian Prantl   // non 8-byte alligned addresses as well.
595c51ad483SPavel Labath   if (addr & 0x07) {
596c51ad483SPavel Labath 
597c51ad483SPavel Labath     addr_t begin = llvm::alignDown(addr, 8);
598c51ad483SPavel Labath     addr_t end = llvm::alignTo(addr + size, 8);
599c51ad483SPavel Labath     size = llvm::PowerOf2Ceil(end - begin);
600c51ad483SPavel Labath 
601c51ad483SPavel Labath     addr = addr & (~0x07);
602c51ad483SPavel Labath   }
603c51ad483SPavel Labath 
604c51ad483SPavel Labath   // Setup control value
605c51ad483SPavel Labath   control_value = watch_flags << 3;
606c51ad483SPavel Labath   control_value |= ((1 << size) - 1) << 5;
607c51ad483SPavel Labath   control_value |= (2 << 1) | 1;
608c51ad483SPavel Labath 
609c51ad483SPavel Labath   // Iterate over stored watchpoints and find a free wp_index
610c51ad483SPavel Labath   wp_index = LLDB_INVALID_INDEX32;
611c51ad483SPavel Labath   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
612c51ad483SPavel Labath     if ((m_hwp_regs[i].control & 1) == 0) {
613c51ad483SPavel Labath       wp_index = i; // Mark last free slot
614c51ad483SPavel Labath     } else if (m_hwp_regs[i].address == addr) {
615c51ad483SPavel Labath       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
616c51ad483SPavel Labath     }
617c51ad483SPavel Labath   }
618c51ad483SPavel Labath 
619c51ad483SPavel Labath   if (wp_index == LLDB_INVALID_INDEX32)
620c51ad483SPavel Labath     return LLDB_INVALID_INDEX32;
621c51ad483SPavel Labath 
622c51ad483SPavel Labath   // Update watchpoint in local cache
623c51ad483SPavel Labath   m_hwp_regs[wp_index].real_addr = real_addr;
624c51ad483SPavel Labath   m_hwp_regs[wp_index].address = addr;
625c51ad483SPavel Labath   m_hwp_regs[wp_index].control = control_value;
626c51ad483SPavel Labath   m_hwp_regs[wp_index].mode = rw_mode;
627c51ad483SPavel Labath 
628c51ad483SPavel Labath   // PTRACE call to set corresponding watchpoint register.
629c51ad483SPavel Labath   error = WriteHardwareDebugRegs();
630c51ad483SPavel Labath 
631c51ad483SPavel Labath   if (error.Fail()) {
632c51ad483SPavel Labath     m_hwp_regs[wp_index].address = 0;
633c51ad483SPavel Labath     m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
634c51ad483SPavel Labath 
635c51ad483SPavel Labath     return LLDB_INVALID_INDEX32;
636c51ad483SPavel Labath   }
637c51ad483SPavel Labath 
638c51ad483SPavel Labath   return wp_index;
639c51ad483SPavel Labath }
640c51ad483SPavel Labath 
641c51ad483SPavel Labath bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
642c51ad483SPavel Labath     uint32_t wp_index) {
643c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
644c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
645c51ad483SPavel Labath 
646c51ad483SPavel Labath   // Read hardware breakpoint and watchpoint information.
647c51ad483SPavel Labath   Status error = ReadHardwareDebugInfo();
648c51ad483SPavel Labath 
649c51ad483SPavel Labath   if (error.Fail())
650c51ad483SPavel Labath     return false;
651c51ad483SPavel Labath 
652c51ad483SPavel Labath   if (wp_index >= m_max_hwp_supported)
653c51ad483SPavel Labath     return false;
654c51ad483SPavel Labath 
655c51ad483SPavel Labath   // Create a backup we can revert to in case of failure.
656c51ad483SPavel Labath   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
657c51ad483SPavel Labath   uint32_t tempControl = m_hwp_regs[wp_index].control;
658c51ad483SPavel Labath   long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
659c51ad483SPavel Labath 
660c51ad483SPavel Labath   // Update watchpoint in local cache
661c51ad483SPavel Labath   m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
662c51ad483SPavel Labath   m_hwp_regs[wp_index].address = 0;
663c51ad483SPavel Labath   m_hwp_regs[wp_index].slot = 0;
664c51ad483SPavel Labath   m_hwp_regs[wp_index].mode = 0;
665c51ad483SPavel Labath 
666c51ad483SPavel Labath   // Ptrace call to update hardware debug registers
667c51ad483SPavel Labath   error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
668c51ad483SPavel Labath                                             m_thread.GetID(), 0, tempSlot);
669c51ad483SPavel Labath 
670c51ad483SPavel Labath   if (error.Fail()) {
671c51ad483SPavel Labath     m_hwp_regs[wp_index].control = tempControl;
672c51ad483SPavel Labath     m_hwp_regs[wp_index].address = tempAddr;
673c51ad483SPavel Labath     m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
674c51ad483SPavel Labath 
675c51ad483SPavel Labath     return false;
676c51ad483SPavel Labath   }
677c51ad483SPavel Labath 
678c51ad483SPavel Labath   return true;
679c51ad483SPavel Labath }
680c51ad483SPavel Labath 
681c51ad483SPavel Labath uint32_t
682c51ad483SPavel Labath NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
683c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
684c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
685c51ad483SPavel Labath 
686c51ad483SPavel Labath   unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
687e6a66105SPavel Labath   if (llvm::isPowerOf2_32(control + 1)) {
688c51ad483SPavel Labath     return llvm::countPopulation(control);
689c51ad483SPavel Labath   }
690c51ad483SPavel Labath 
691e6a66105SPavel Labath   return 0;
692e6a66105SPavel Labath }
693e6a66105SPavel Labath 
694c51ad483SPavel Labath bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
695c51ad483SPavel Labath     uint32_t wp_index) {
696c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
697c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
698c51ad483SPavel Labath 
699c51ad483SPavel Labath   return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
700c51ad483SPavel Labath }
701c51ad483SPavel Labath 
702c51ad483SPavel Labath Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
703c51ad483SPavel Labath     uint32_t &wp_index, lldb::addr_t trap_addr) {
704c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
705c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
706c51ad483SPavel Labath 
707c51ad483SPavel Labath   uint32_t watch_size;
708c51ad483SPavel Labath   lldb::addr_t watch_addr;
709c51ad483SPavel Labath 
710c51ad483SPavel Labath   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
711c51ad483SPavel Labath     watch_size = GetWatchpointSize(wp_index);
712c51ad483SPavel Labath     watch_addr = m_hwp_regs[wp_index].address;
713c51ad483SPavel Labath 
714c51ad483SPavel Labath     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
715c51ad483SPavel Labath         trap_addr <= watch_addr + watch_size) {
716c51ad483SPavel Labath       m_hwp_regs[wp_index].hit_addr = trap_addr;
717c51ad483SPavel Labath       return Status();
718c51ad483SPavel Labath     }
719c51ad483SPavel Labath   }
720c51ad483SPavel Labath 
721c51ad483SPavel Labath   wp_index = LLDB_INVALID_INDEX32;
722c51ad483SPavel Labath   return Status();
723c51ad483SPavel Labath }
724c51ad483SPavel Labath 
725c51ad483SPavel Labath lldb::addr_t
726c51ad483SPavel Labath NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
727c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
728c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
729c51ad483SPavel Labath 
730c51ad483SPavel Labath   if (wp_index >= m_max_hwp_supported)
731c51ad483SPavel Labath     return LLDB_INVALID_ADDRESS;
732c51ad483SPavel Labath 
733c51ad483SPavel Labath   if (WatchpointIsEnabled(wp_index))
734c51ad483SPavel Labath     return m_hwp_regs[wp_index].real_addr;
735c51ad483SPavel Labath   else
736c51ad483SPavel Labath     return LLDB_INVALID_ADDRESS;
737c51ad483SPavel Labath }
738c51ad483SPavel Labath 
739c51ad483SPavel Labath lldb::addr_t
740c51ad483SPavel Labath NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
741c51ad483SPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
742c51ad483SPavel Labath   LLDB_LOG(log, "wp_index: {0}", wp_index);
743c51ad483SPavel Labath 
744c51ad483SPavel Labath   if (wp_index >= m_max_hwp_supported)
745c51ad483SPavel Labath     return LLDB_INVALID_ADDRESS;
746c51ad483SPavel Labath 
747c51ad483SPavel Labath   if (WatchpointIsEnabled(wp_index))
748c51ad483SPavel Labath     return m_hwp_regs[wp_index].hit_addr;
749c51ad483SPavel Labath 
750c51ad483SPavel Labath   return LLDB_INVALID_ADDRESS;
751c51ad483SPavel Labath }
752c51ad483SPavel Labath 
753c51ad483SPavel Labath Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
754c51ad483SPavel Labath   if (!m_refresh_hwdebug_info) {
755c51ad483SPavel Labath     return Status();
756c51ad483SPavel Labath   }
757c51ad483SPavel Labath 
758c51ad483SPavel Labath   ::pid_t tid = m_thread.GetID();
759c51ad483SPavel Labath 
760c51ad483SPavel Labath   struct ppc_debug_info hwdebug_info;
761c51ad483SPavel Labath   Status error;
762c51ad483SPavel Labath 
763c51ad483SPavel Labath   error = NativeProcessLinux::PtraceWrapper(
764c51ad483SPavel Labath       PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
765c51ad483SPavel Labath 
766c51ad483SPavel Labath   if (error.Fail())
767c51ad483SPavel Labath     return error;
768c51ad483SPavel Labath 
769c51ad483SPavel Labath   m_max_hwp_supported = hwdebug_info.num_data_bps;
770c51ad483SPavel Labath   m_max_hbp_supported = hwdebug_info.num_instruction_bps;
771c51ad483SPavel Labath   m_refresh_hwdebug_info = false;
772c51ad483SPavel Labath 
773c51ad483SPavel Labath   return error;
774c51ad483SPavel Labath }
775c51ad483SPavel Labath 
776c51ad483SPavel Labath Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
777c51ad483SPavel Labath   struct ppc_hw_breakpoint reg_state;
778c51ad483SPavel Labath   Status error;
779c51ad483SPavel Labath   long ret;
780c51ad483SPavel Labath 
781c51ad483SPavel Labath   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
782c51ad483SPavel Labath     reg_state.addr = m_hwp_regs[i].address;
783c51ad483SPavel Labath     reg_state.trigger_type = m_hwp_regs[i].mode;
784c51ad483SPavel Labath     reg_state.version = 1;
785c51ad483SPavel Labath     reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
786c51ad483SPavel Labath     reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
787c51ad483SPavel Labath     reg_state.addr2 = 0;
788c51ad483SPavel Labath     reg_state.condition_value = 0;
789c51ad483SPavel Labath 
790c51ad483SPavel Labath     error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
791c51ad483SPavel Labath                                               m_thread.GetID(), 0, &reg_state,
792c51ad483SPavel Labath                                               sizeof(reg_state), &ret);
793c51ad483SPavel Labath 
794c51ad483SPavel Labath     if (error.Fail())
795c51ad483SPavel Labath       return error;
796c51ad483SPavel Labath 
797c51ad483SPavel Labath     m_hwp_regs[i].slot = ret;
798c51ad483SPavel Labath   }
799c51ad483SPavel Labath 
800c51ad483SPavel Labath   return error;
801c51ad483SPavel Labath }
802c51ad483SPavel Labath 
803aae0a752SEugene Zemtsov #endif // defined(__powerpc64__)
804