180814287SRaphael Isemann //===-- NativeRegisterContextLinux_s390x.cpp ------------------------------===//
2bb00d0b6SUlrich Weigand //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bb00d0b6SUlrich Weigand //
7bb00d0b6SUlrich Weigand //===----------------------------------------------------------------------===//
8bb00d0b6SUlrich Weigand 
9bb00d0b6SUlrich Weigand #if defined(__s390x__) && defined(__linux__)
10bb00d0b6SUlrich Weigand 
11bb00d0b6SUlrich Weigand #include "NativeRegisterContextLinux_s390x.h"
1201961c4bSPavel Labath #include "Plugins/Process/Linux/NativeProcessLinux.h"
13bb00d0b6SUlrich Weigand #include "lldb/Host/HostInfo.h"
14666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
156f9e6901SZachary Turner #include "lldb/Utility/Log.h"
16d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
1797206d57SZachary Turner #include "lldb/Utility/Status.h"
18bb00d0b6SUlrich Weigand 
19bb00d0b6SUlrich Weigand #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
20bb00d0b6SUlrich Weigand 
21bb00d0b6SUlrich Weigand #include <linux/uio.h>
22bb00d0b6SUlrich Weigand #include <sys/ptrace.h>
23bb00d0b6SUlrich Weigand 
24bb00d0b6SUlrich Weigand using namespace lldb_private;
25bb00d0b6SUlrich Weigand using namespace lldb_private::process_linux;
26bb00d0b6SUlrich Weigand 
27bb00d0b6SUlrich Weigand // Private namespace.
28bb00d0b6SUlrich Weigand 
29b9c1b51eSKate Stone namespace {
30bb00d0b6SUlrich Weigand // s390x 64-bit general purpose registers.
31b9c1b51eSKate Stone static const uint32_t g_gpr_regnums_s390x[] = {
32b9c1b51eSKate Stone     lldb_r0_s390x,      lldb_r1_s390x,    lldb_r2_s390x,    lldb_r3_s390x,
33b9c1b51eSKate Stone     lldb_r4_s390x,      lldb_r5_s390x,    lldb_r6_s390x,    lldb_r7_s390x,
34b9c1b51eSKate Stone     lldb_r8_s390x,      lldb_r9_s390x,    lldb_r10_s390x,   lldb_r11_s390x,
35b9c1b51eSKate Stone     lldb_r12_s390x,     lldb_r13_s390x,   lldb_r14_s390x,   lldb_r15_s390x,
36b9c1b51eSKate Stone     lldb_acr0_s390x,    lldb_acr1_s390x,  lldb_acr2_s390x,  lldb_acr3_s390x,
37b9c1b51eSKate Stone     lldb_acr4_s390x,    lldb_acr5_s390x,  lldb_acr6_s390x,  lldb_acr7_s390x,
38b9c1b51eSKate Stone     lldb_acr8_s390x,    lldb_acr9_s390x,  lldb_acr10_s390x, lldb_acr11_s390x,
39b9c1b51eSKate Stone     lldb_acr12_s390x,   lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
40b9c1b51eSKate Stone     lldb_pswm_s390x,    lldb_pswa_s390x,
41bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
42bb00d0b6SUlrich Weigand };
43b9c1b51eSKate Stone static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
44b9c1b51eSKate Stone                       1 ==
45b9c1b51eSKate Stone                   k_num_gpr_registers_s390x,
46bb00d0b6SUlrich Weigand               "g_gpr_regnums_s390x has wrong number of register infos");
47bb00d0b6SUlrich Weigand 
48bb00d0b6SUlrich Weigand // s390x 64-bit floating point registers.
49b9c1b51eSKate Stone static const uint32_t g_fpu_regnums_s390x[] = {
50b9c1b51eSKate Stone     lldb_f0_s390x,      lldb_f1_s390x,  lldb_f2_s390x,  lldb_f3_s390x,
51b9c1b51eSKate Stone     lldb_f4_s390x,      lldb_f5_s390x,  lldb_f6_s390x,  lldb_f7_s390x,
52b9c1b51eSKate Stone     lldb_f8_s390x,      lldb_f9_s390x,  lldb_f10_s390x, lldb_f11_s390x,
53b9c1b51eSKate Stone     lldb_f12_s390x,     lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
54bb00d0b6SUlrich Weigand     lldb_fpc_s390x,
55bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
56bb00d0b6SUlrich Weigand };
57b9c1b51eSKate Stone static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
58b9c1b51eSKate Stone                       1 ==
59b9c1b51eSKate Stone                   k_num_fpr_registers_s390x,
60bb00d0b6SUlrich Weigand               "g_fpu_regnums_s390x has wrong number of register infos");
61bb00d0b6SUlrich Weigand 
62bb00d0b6SUlrich Weigand // s390x Linux operating-system information.
63b9c1b51eSKate Stone static const uint32_t g_linux_regnums_s390x[] = {
64b9c1b51eSKate Stone     lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x,
65bb00d0b6SUlrich Weigand     LLDB_INVALID_REGNUM // register sets need to end with this flag
66bb00d0b6SUlrich Weigand };
67b9c1b51eSKate Stone static_assert((sizeof(g_linux_regnums_s390x) /
68b9c1b51eSKate Stone                sizeof(g_linux_regnums_s390x[0])) -
69b9c1b51eSKate Stone                       1 ==
70b9c1b51eSKate Stone                   k_num_linux_registers_s390x,
71bb00d0b6SUlrich Weigand               "g_linux_regnums_s390x has wrong number of register infos");
72bb00d0b6SUlrich Weigand 
73bb00d0b6SUlrich Weigand // Number of register sets provided by this context.
74b9c1b51eSKate Stone enum { k_num_register_sets = 3 };
75bb00d0b6SUlrich Weigand 
76bb00d0b6SUlrich Weigand // Register sets for s390x 64-bit.
77b9c1b51eSKate Stone static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
78b9c1b51eSKate Stone     {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
79b9c1b51eSKate Stone      g_gpr_regnums_s390x},
80b9c1b51eSKate Stone     {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
81b9c1b51eSKate Stone      g_fpu_regnums_s390x},
82b9c1b51eSKate Stone     {"Linux Operating System Data", "linux", k_num_linux_registers_s390x,
83b9c1b51eSKate Stone      g_linux_regnums_s390x},
84bb00d0b6SUlrich Weigand };
85bb00d0b6SUlrich Weigand }
86bb00d0b6SUlrich Weigand 
87bb00d0b6SUlrich Weigand #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4)
88bb00d0b6SUlrich Weigand 
89bb00d0b6SUlrich Weigand // Required ptrace defines.
90bb00d0b6SUlrich Weigand 
91bb00d0b6SUlrich Weigand #define NT_S390_LAST_BREAK 0x306  /* s390 breaking event address */
92bb00d0b6SUlrich Weigand #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
93bb00d0b6SUlrich Weigand 
94d37349f3SPavel Labath std::unique_ptr<NativeRegisterContextLinux>
95b9c1b51eSKate Stone NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
96d1486e65SPavel Labath     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
97a8f3ae7cSJonas Devlieghere   return std::make_unique<NativeRegisterContextLinux_s390x>(target_arch,
98d37349f3SPavel Labath                                                              native_thread);
99bb00d0b6SUlrich Weigand }
100bb00d0b6SUlrich Weigand 
101bb00d0b6SUlrich Weigand // NativeRegisterContextLinux_s390x members.
102bb00d0b6SUlrich Weigand 
103bb00d0b6SUlrich Weigand static RegisterInfoInterface *
104b9c1b51eSKate Stone CreateRegisterInfoInterface(const ArchSpec &target_arch) {
105bb00d0b6SUlrich Weigand   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
106bb00d0b6SUlrich Weigand          "Register setting path assumes this is a 64-bit host");
107bb00d0b6SUlrich Weigand   return new RegisterContextLinux_s390x(target_arch);
108bb00d0b6SUlrich Weigand }
109bb00d0b6SUlrich Weigand 
110b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(
111d37349f3SPavel Labath     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
112f5ca2756SMichał Górny     : NativeRegisterContextRegisterInfo(
113*e1d4fb1eSPavel Labath           native_thread, CreateRegisterInfoInterface(target_arch)),
114*e1d4fb1eSPavel Labath       NativeRegisterContextLinux(native_thread) {
115bb00d0b6SUlrich Weigand   // Set up data about ranges of valid registers.
116b9c1b51eSKate Stone   switch (target_arch.GetMachine()) {
117bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
118bb00d0b6SUlrich Weigand     m_reg_info.num_registers = k_num_registers_s390x;
119bb00d0b6SUlrich Weigand     m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
120bb00d0b6SUlrich Weigand     m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
121bb00d0b6SUlrich Weigand     m_reg_info.last_gpr = k_last_gpr_s390x;
122bb00d0b6SUlrich Weigand     m_reg_info.first_fpr = k_first_fpr_s390x;
123bb00d0b6SUlrich Weigand     m_reg_info.last_fpr = k_last_fpr_s390x;
124bb00d0b6SUlrich Weigand     break;
125bb00d0b6SUlrich Weigand   default:
126bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
127bb00d0b6SUlrich Weigand     break;
128bb00d0b6SUlrich Weigand   }
129bb00d0b6SUlrich Weigand 
130bb00d0b6SUlrich Weigand   // Clear out the watchpoint state.
131bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
132bb00d0b6SUlrich Weigand }
133bb00d0b6SUlrich Weigand 
134b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
135bb00d0b6SUlrich Weigand   uint32_t sets = 0;
136b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
137bb00d0b6SUlrich Weigand     if (IsRegisterSetAvailable(set_index))
138bb00d0b6SUlrich Weigand       ++sets;
139bb00d0b6SUlrich Weigand   }
140bb00d0b6SUlrich Weigand 
141bb00d0b6SUlrich Weigand   return sets;
142bb00d0b6SUlrich Weigand }
143bb00d0b6SUlrich Weigand 
144b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
145bb00d0b6SUlrich Weigand   uint32_t count = 0;
146b9c1b51eSKate Stone   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
147bb00d0b6SUlrich Weigand     const RegisterSet *set = GetRegisterSet(set_index);
148bb00d0b6SUlrich Weigand     if (set)
149bb00d0b6SUlrich Weigand       count += set->num_registers;
150bb00d0b6SUlrich Weigand   }
151bb00d0b6SUlrich Weigand   return count;
152bb00d0b6SUlrich Weigand }
153bb00d0b6SUlrich Weigand 
154bb00d0b6SUlrich Weigand const RegisterSet *
155b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
156bb00d0b6SUlrich Weigand   if (!IsRegisterSetAvailable(set_index))
157bb00d0b6SUlrich Weigand     return nullptr;
158bb00d0b6SUlrich Weigand 
159b9c1b51eSKate Stone   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
160bb00d0b6SUlrich Weigand   case llvm::Triple::systemz:
161bb00d0b6SUlrich Weigand     return &g_reg_sets_s390x[set_index];
162bb00d0b6SUlrich Weigand   default:
163bb00d0b6SUlrich Weigand     assert(false && "Unhandled target architecture.");
164bb00d0b6SUlrich Weigand     return nullptr;
165bb00d0b6SUlrich Weigand   }
166bb00d0b6SUlrich Weigand 
167bb00d0b6SUlrich Weigand   return nullptr;
168bb00d0b6SUlrich Weigand }
169bb00d0b6SUlrich Weigand 
170b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
171b9c1b51eSKate Stone     uint32_t set_index) const {
172bb00d0b6SUlrich Weigand   return set_index < k_num_register_sets;
173bb00d0b6SUlrich Weigand }
174bb00d0b6SUlrich Weigand 
175b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
176b9c1b51eSKate Stone   // GPRs come first.  "orig_r2" counts as GPR since it is part of the GPR
177b9c1b51eSKate Stone   // register area.
178bb00d0b6SUlrich Weigand   return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
179bb00d0b6SUlrich Weigand }
180bb00d0b6SUlrich Weigand 
181b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
182b9c1b51eSKate Stone   return (m_reg_info.first_fpr <= reg_index &&
183b9c1b51eSKate Stone           reg_index <= m_reg_info.last_fpr);
184bb00d0b6SUlrich Weigand }
185bb00d0b6SUlrich Weigand 
18697206d57SZachary Turner Status
18797206d57SZachary Turner NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info,
18897206d57SZachary Turner                                                RegisterValue &reg_value) {
189bb00d0b6SUlrich Weigand   if (!reg_info)
19097206d57SZachary Turner     return Status("reg_info NULL");
191bb00d0b6SUlrich Weigand 
192bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
193bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
19497206d57SZachary Turner     return Status("register \"%s\" is an internal-only lldb register, cannot "
195b9c1b51eSKate Stone                   "read directly",
196b9c1b51eSKate Stone                   reg_info->name);
197bb00d0b6SUlrich Weigand 
198b9c1b51eSKate Stone   if (IsGPR(reg)) {
1993f3673eaSPavel Labath     Status error = ReadGPR();
200bb00d0b6SUlrich Weigand     if (error.Fail())
201bb00d0b6SUlrich Weigand       return error;
202bb00d0b6SUlrich Weigand 
2033f3673eaSPavel Labath     uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset;
2043f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
205b9c1b51eSKate Stone     switch (reg_info->byte_size) {
206bb00d0b6SUlrich Weigand     case 4:
207bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
208bb00d0b6SUlrich Weigand       break;
209bb00d0b6SUlrich Weigand     case 8:
210bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
211bb00d0b6SUlrich Weigand       break;
212bb00d0b6SUlrich Weigand     default:
213bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
21497206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
215bb00d0b6SUlrich Weigand     }
21697206d57SZachary Turner     return Status();
217bb00d0b6SUlrich Weigand   }
218bb00d0b6SUlrich Weigand 
219b9c1b51eSKate Stone   if (IsFPR(reg)) {
2203f3673eaSPavel Labath     Status error = ReadFPR();
221bb00d0b6SUlrich Weigand     if (error.Fail())
222bb00d0b6SUlrich Weigand       return error;
223bb00d0b6SUlrich Weigand 
224bb00d0b6SUlrich Weigand     // byte_offset is just the offset within FPR, not the whole user area.
2253f3673eaSPavel Labath     uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
2263f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
227b9c1b51eSKate Stone     switch (reg_info->byte_size) {
228bb00d0b6SUlrich Weigand     case 4:
229bb00d0b6SUlrich Weigand       reg_value.SetUInt32(*(uint32_t *)src);
230bb00d0b6SUlrich Weigand       break;
231bb00d0b6SUlrich Weigand     case 8:
232bb00d0b6SUlrich Weigand       reg_value.SetUInt64(*(uint64_t *)src);
233bb00d0b6SUlrich Weigand       break;
234bb00d0b6SUlrich Weigand     default:
235bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
23697206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
237bb00d0b6SUlrich Weigand     }
23897206d57SZachary Turner     return Status();
239bb00d0b6SUlrich Weigand   }
240bb00d0b6SUlrich Weigand 
241b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
242bb00d0b6SUlrich Weigand     uint64_t last_break;
24397206d57SZachary Turner     Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
244bb00d0b6SUlrich Weigand     if (error.Fail())
245bb00d0b6SUlrich Weigand       return error;
246bb00d0b6SUlrich Weigand 
247bb00d0b6SUlrich Weigand     reg_value.SetUInt64(last_break);
24897206d57SZachary Turner     return Status();
249bb00d0b6SUlrich Weigand   }
250bb00d0b6SUlrich Weigand 
251b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
252bb00d0b6SUlrich Weigand     uint32_t system_call;
25397206d57SZachary Turner     Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
254bb00d0b6SUlrich Weigand     if (error.Fail())
255bb00d0b6SUlrich Weigand       return error;
256bb00d0b6SUlrich Weigand 
257bb00d0b6SUlrich Weigand     reg_value.SetUInt32(system_call);
25897206d57SZachary Turner     return Status();
259bb00d0b6SUlrich Weigand   }
260bb00d0b6SUlrich Weigand 
26197206d57SZachary Turner   return Status("failed - register wasn't recognized");
262bb00d0b6SUlrich Weigand }
263bb00d0b6SUlrich Weigand 
26497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteRegister(
265b9c1b51eSKate Stone     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
266bb00d0b6SUlrich Weigand   if (!reg_info)
26797206d57SZachary Turner     return Status("reg_info NULL");
268bb00d0b6SUlrich Weigand 
269bb00d0b6SUlrich Weigand   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
270bb00d0b6SUlrich Weigand   if (reg == LLDB_INVALID_REGNUM)
27197206d57SZachary Turner     return Status("register \"%s\" is an internal-only lldb register, cannot "
272b9c1b51eSKate Stone                   "write directly",
273b9c1b51eSKate Stone                   reg_info->name);
274bb00d0b6SUlrich Weigand 
275b9c1b51eSKate Stone   if (IsGPR(reg)) {
2763f3673eaSPavel Labath     Status error = ReadGPR();
277bb00d0b6SUlrich Weigand     if (error.Fail())
278bb00d0b6SUlrich Weigand       return error;
279bb00d0b6SUlrich Weigand 
2803f3673eaSPavel Labath     uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset;
2813f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
282b9c1b51eSKate Stone     switch (reg_info->byte_size) {
283bb00d0b6SUlrich Weigand     case 4:
284bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
285bb00d0b6SUlrich Weigand       break;
286bb00d0b6SUlrich Weigand     case 8:
287bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
288bb00d0b6SUlrich Weigand       break;
289bb00d0b6SUlrich Weigand     default:
290bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
29197206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
292bb00d0b6SUlrich Weigand     }
2933f3673eaSPavel Labath     return WriteGPR();
294bb00d0b6SUlrich Weigand   }
295bb00d0b6SUlrich Weigand 
296b9c1b51eSKate Stone   if (IsFPR(reg)) {
2973f3673eaSPavel Labath     Status error = ReadFPR();
298bb00d0b6SUlrich Weigand     if (error.Fail())
299bb00d0b6SUlrich Weigand       return error;
300bb00d0b6SUlrich Weigand 
301bb00d0b6SUlrich Weigand     // byte_offset is just the offset within fp_regs, not the whole user area.
3023f3673eaSPavel Labath     uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
3033f3673eaSPavel Labath     assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
304b9c1b51eSKate Stone     switch (reg_info->byte_size) {
305bb00d0b6SUlrich Weigand     case 4:
306bb00d0b6SUlrich Weigand       *(uint32_t *)dst = reg_value.GetAsUInt32();
307bb00d0b6SUlrich Weigand       break;
308bb00d0b6SUlrich Weigand     case 8:
309bb00d0b6SUlrich Weigand       *(uint64_t *)dst = reg_value.GetAsUInt64();
310bb00d0b6SUlrich Weigand       break;
311bb00d0b6SUlrich Weigand     default:
312bb00d0b6SUlrich Weigand       assert(false && "Unhandled data size.");
31397206d57SZachary Turner       return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
314bb00d0b6SUlrich Weigand     }
3153f3673eaSPavel Labath     return WriteFPR();
316bb00d0b6SUlrich Weigand   }
317bb00d0b6SUlrich Weigand 
318b9c1b51eSKate Stone   if (reg == lldb_last_break_s390x) {
31997206d57SZachary Turner     return Status("The last break address is read-only");
320bb00d0b6SUlrich Weigand   }
321bb00d0b6SUlrich Weigand 
322b9c1b51eSKate Stone   if (reg == lldb_system_call_s390x) {
323bb00d0b6SUlrich Weigand     uint32_t system_call = reg_value.GetAsUInt32();
324bb00d0b6SUlrich Weigand     return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
325bb00d0b6SUlrich Weigand   }
326bb00d0b6SUlrich Weigand 
32797206d57SZachary Turner   return Status("failed - register wasn't recognized");
328bb00d0b6SUlrich Weigand }
329bb00d0b6SUlrich Weigand 
33097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
331b9c1b51eSKate Stone     lldb::DataBufferSP &data_sp) {
33297206d57SZachary Turner   Status error;
333bb00d0b6SUlrich Weigand 
334bb00d0b6SUlrich Weigand   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
335bb00d0b6SUlrich Weigand   uint8_t *dst = data_sp->GetBytes();
3363f3673eaSPavel Labath   error = ReadGPR();
337bb00d0b6SUlrich Weigand   if (error.Fail())
338bb00d0b6SUlrich Weigand     return error;
3393f3673eaSPavel Labath   memcpy(dst, GetGPRBuffer(), GetGPRSize());
3403f3673eaSPavel Labath   dst += GetGPRSize();
341bb00d0b6SUlrich Weigand 
3423f3673eaSPavel Labath   error = ReadFPR();
343bb00d0b6SUlrich Weigand   if (error.Fail())
344bb00d0b6SUlrich Weigand     return error;
3453f3673eaSPavel Labath   memcpy(dst, GetFPRBuffer(), GetFPRSize());
3463f3673eaSPavel Labath   dst += GetFPRSize();
347bb00d0b6SUlrich Weigand 
348bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
349bb00d0b6SUlrich Weigand   DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
350bb00d0b6SUlrich Weigand   dst += 4;
351bb00d0b6SUlrich Weigand 
35205097246SAdrian Prantl   // To enable inferior function calls while the process is stopped in an
35305097246SAdrian Prantl   // interrupted system call, we need to clear the system call flag. It will be
35405097246SAdrian Prantl   // restored to its original value by WriteAllRegisterValues. Again we ignore
35505097246SAdrian Prantl   // error if the regset is unsupported.
356bb00d0b6SUlrich Weigand   uint32_t system_call = 0;
357bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
358bb00d0b6SUlrich Weigand 
359bb00d0b6SUlrich Weigand   return error;
360bb00d0b6SUlrich Weigand }
361bb00d0b6SUlrich Weigand 
36297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
363b9c1b51eSKate Stone     const lldb::DataBufferSP &data_sp) {
36497206d57SZachary Turner   Status error;
365bb00d0b6SUlrich Weigand 
366b9c1b51eSKate Stone   if (!data_sp) {
367b9c1b51eSKate Stone     error.SetErrorStringWithFormat(
368b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
369b9c1b51eSKate Stone         __FUNCTION__);
370bb00d0b6SUlrich Weigand     return error;
371bb00d0b6SUlrich Weigand   }
372bb00d0b6SUlrich Weigand 
373b9c1b51eSKate Stone   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
374bb00d0b6SUlrich Weigand     error.SetErrorStringWithFormat(
375b9c1b51eSKate Stone         "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
376b9c1b51eSKate Stone         "data size, expected %" PRIu64 ", actual %" PRIu64,
377bb00d0b6SUlrich Weigand         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
378bb00d0b6SUlrich Weigand     return error;
379bb00d0b6SUlrich Weigand   }
380bb00d0b6SUlrich Weigand 
3813f3673eaSPavel Labath   const uint8_t *src = data_sp->GetBytes();
382b9c1b51eSKate Stone   if (src == nullptr) {
383b9c1b51eSKate Stone     error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
384b9c1b51eSKate Stone                                    "DataBuffer::GetBytes() returned a null "
385b9c1b51eSKate Stone                                    "pointer",
386b9c1b51eSKate Stone                                    __FUNCTION__);
387bb00d0b6SUlrich Weigand     return error;
388bb00d0b6SUlrich Weigand   }
389bb00d0b6SUlrich Weigand 
3903f3673eaSPavel Labath   memcpy(GetGPRBuffer(), src, GetGPRSize());
3913f3673eaSPavel Labath   src += GetGPRSize();
3923f3673eaSPavel Labath   error = WriteGPR();
393bb00d0b6SUlrich Weigand   if (error.Fail())
394bb00d0b6SUlrich Weigand     return error;
395bb00d0b6SUlrich Weigand 
3963f3673eaSPavel Labath   memcpy(GetFPRBuffer(), src, GetFPRSize());
3973f3673eaSPavel Labath   src += GetFPRSize();
3983f3673eaSPavel Labath   error = WriteFPR();
399bb00d0b6SUlrich Weigand   if (error.Fail())
400bb00d0b6SUlrich Weigand     return error;
401bb00d0b6SUlrich Weigand 
402bb00d0b6SUlrich Weigand   // Ignore errors if the regset is unsupported (happens on older kernels).
403bb00d0b6SUlrich Weigand   DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
404bb00d0b6SUlrich Weigand   src += 4;
405bb00d0b6SUlrich Weigand 
406bb00d0b6SUlrich Weigand   return error;
407bb00d0b6SUlrich Weigand }
408bb00d0b6SUlrich Weigand 
40997206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterValue(
410b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, uint32_t size,
411b9c1b51eSKate Stone     RegisterValue &value) {
41297206d57SZachary Turner   return Status("DoReadRegisterValue unsupported");
413bb00d0b6SUlrich Weigand }
414bb00d0b6SUlrich Weigand 
41597206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
416b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
41797206d57SZachary Turner   return Status("DoWriteRegisterValue unsupported");
418bb00d0b6SUlrich Weigand }
419bb00d0b6SUlrich Weigand 
42097206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset,
42197206d57SZachary Turner                                                       void *buf,
422b9c1b51eSKate Stone                                                       size_t buf_size) {
423bb00d0b6SUlrich Weigand   ptrace_area parea;
424bb00d0b6SUlrich Weigand   parea.len = buf_size;
425bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
426bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
427bb00d0b6SUlrich Weigand 
428b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
429b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
430bb00d0b6SUlrich Weigand }
431bb00d0b6SUlrich Weigand 
43297206d57SZachary Turner Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
433b9c1b51eSKate Stone                                                       const void *buf,
434b9c1b51eSKate Stone                                                       size_t buf_size) {
435bb00d0b6SUlrich Weigand   ptrace_area parea;
436bb00d0b6SUlrich Weigand   parea.len = buf_size;
437bb00d0b6SUlrich Weigand   parea.process_addr = (addr_t)buf;
438bb00d0b6SUlrich Weigand   parea.kernel_addr = offset;
439bb00d0b6SUlrich Weigand 
440b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
441b9c1b51eSKate Stone                                            m_thread.GetID(), &parea);
442bb00d0b6SUlrich Weigand }
443bb00d0b6SUlrich Weigand 
4443f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadGPR() {
4453f3673eaSPavel Labath   return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
4463f3673eaSPavel Labath                       GetGPRSize());
447bb00d0b6SUlrich Weigand }
448bb00d0b6SUlrich Weigand 
4493f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteGPR() {
4503f3673eaSPavel Labath   return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
4513f3673eaSPavel Labath                       GetGPRSize());
452bb00d0b6SUlrich Weigand }
453bb00d0b6SUlrich Weigand 
4543f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::ReadFPR() {
4553f3673eaSPavel Labath   return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
4563f3673eaSPavel Labath                       GetGPRSize());
457bb00d0b6SUlrich Weigand }
458bb00d0b6SUlrich Weigand 
4593f3673eaSPavel Labath Status NativeRegisterContextLinux_s390x::WriteFPR() {
4603f3673eaSPavel Labath   return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
4613f3673eaSPavel Labath                       GetGPRSize());
462bb00d0b6SUlrich Weigand }
463bb00d0b6SUlrich Weigand 
46497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
465b9c1b51eSKate Stone                                                            void *buf,
466b9c1b51eSKate Stone                                                            size_t buf_size) {
467bb00d0b6SUlrich Weigand   struct iovec iov;
468bb00d0b6SUlrich Weigand   iov.iov_base = buf;
469bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
470bb00d0b6SUlrich Weigand 
471bb00d0b6SUlrich Weigand   return ReadRegisterSet(&iov, buf_size, regset);
472bb00d0b6SUlrich Weigand }
473bb00d0b6SUlrich Weigand 
47497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
475b9c1b51eSKate Stone                                                             const void *buf,
476b9c1b51eSKate Stone                                                             size_t buf_size) {
477bb00d0b6SUlrich Weigand   struct iovec iov;
478bb00d0b6SUlrich Weigand   iov.iov_base = const_cast<void *>(buf);
479bb00d0b6SUlrich Weigand   iov.iov_len = buf_size;
480bb00d0b6SUlrich Weigand 
481bb00d0b6SUlrich Weigand   return WriteRegisterSet(&iov, buf_size, regset);
482bb00d0b6SUlrich Weigand }
483bb00d0b6SUlrich Weigand 
48497206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
485b9c1b51eSKate Stone                                                          bool &is_hit) {
486bb00d0b6SUlrich Weigand   per_lowcore_bits per_lowcore;
487bb00d0b6SUlrich Weigand 
488bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
48997206d57SZachary Turner     return Status("Watchpoint index out of range");
490bb00d0b6SUlrich Weigand 
491b9c1b51eSKate Stone   if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
492bb00d0b6SUlrich Weigand     is_hit = false;
49397206d57SZachary Turner     return Status();
494bb00d0b6SUlrich Weigand   }
495bb00d0b6SUlrich Weigand 
49697206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
497b9c1b51eSKate Stone                               &per_lowcore, sizeof(per_lowcore));
498b9c1b51eSKate Stone   if (error.Fail()) {
499bb00d0b6SUlrich Weigand     is_hit = false;
500bb00d0b6SUlrich Weigand     return error;
501bb00d0b6SUlrich Weigand   }
502bb00d0b6SUlrich Weigand 
503b9c1b51eSKate Stone   is_hit = (per_lowcore.perc_storage_alteration == 1 &&
504b9c1b51eSKate Stone             per_lowcore.perc_store_real_address == 0);
505bb00d0b6SUlrich Weigand 
506b9c1b51eSKate Stone   if (is_hit) {
507bb00d0b6SUlrich Weigand     // Do not report this watchpoint again.
508bb00d0b6SUlrich Weigand     memset(&per_lowcore, 0, sizeof(per_lowcore));
509b9c1b51eSKate Stone     PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
510b9c1b51eSKate Stone                  sizeof(per_lowcore));
511bb00d0b6SUlrich Weigand   }
512bb00d0b6SUlrich Weigand 
51397206d57SZachary Turner   return Status();
514bb00d0b6SUlrich Weigand }
515bb00d0b6SUlrich Weigand 
51697206d57SZachary Turner Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
517b9c1b51eSKate Stone     uint32_t &wp_index, lldb::addr_t trap_addr) {
518bb00d0b6SUlrich Weigand   uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
519b9c1b51eSKate Stone   for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
520bb00d0b6SUlrich Weigand     bool is_hit;
52197206d57SZachary Turner     Status error = IsWatchpointHit(wp_index, is_hit);
522b9c1b51eSKate Stone     if (error.Fail()) {
523bb00d0b6SUlrich Weigand       wp_index = LLDB_INVALID_INDEX32;
524bb00d0b6SUlrich Weigand       return error;
525b9c1b51eSKate Stone     } else if (is_hit) {
526bb00d0b6SUlrich Weigand       return error;
527bb00d0b6SUlrich Weigand     }
528bb00d0b6SUlrich Weigand   }
529bb00d0b6SUlrich Weigand   wp_index = LLDB_INVALID_INDEX32;
53097206d57SZachary Turner   return Status();
531bb00d0b6SUlrich Weigand }
532bb00d0b6SUlrich Weigand 
53397206d57SZachary Turner Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
534b9c1b51eSKate Stone                                                             bool &is_vacant) {
535bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
53697206d57SZachary Turner     return Status("Watchpoint index out of range");
537bb00d0b6SUlrich Weigand 
538bb00d0b6SUlrich Weigand   is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
539bb00d0b6SUlrich Weigand 
54097206d57SZachary Turner   return Status();
541bb00d0b6SUlrich Weigand }
542bb00d0b6SUlrich Weigand 
543b9c1b51eSKate Stone bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
544b9c1b51eSKate Stone     uint32_t wp_index) {
545bb00d0b6SUlrich Weigand   per_struct per_info;
546bb00d0b6SUlrich Weigand 
547bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
548bb00d0b6SUlrich Weigand     return false;
549bb00d0b6SUlrich Weigand 
55097206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
551b9c1b51eSKate Stone                               sizeof(per_info));
552bb00d0b6SUlrich Weigand   if (error.Fail())
553bb00d0b6SUlrich Weigand     return false;
554bb00d0b6SUlrich Weigand 
555bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 0;
556bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 0;
557bb00d0b6SUlrich Weigand   per_info.starting_addr = 0;
558bb00d0b6SUlrich Weigand   per_info.ending_addr = 0;
559bb00d0b6SUlrich Weigand 
560b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
561b9c1b51eSKate Stone                        sizeof(per_info));
562bb00d0b6SUlrich Weigand   if (error.Fail())
563bb00d0b6SUlrich Weigand     return false;
564bb00d0b6SUlrich Weigand 
565bb00d0b6SUlrich Weigand   m_watchpoint_addr = LLDB_INVALID_ADDRESS;
566bb00d0b6SUlrich Weigand   return true;
567bb00d0b6SUlrich Weigand }
568bb00d0b6SUlrich Weigand 
56997206d57SZachary Turner Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
570bb00d0b6SUlrich Weigand   if (ClearHardwareWatchpoint(0))
57197206d57SZachary Turner     return Status();
57297206d57SZachary Turner   return Status("Clearing all hardware watchpoints failed.");
573bb00d0b6SUlrich Weigand }
574bb00d0b6SUlrich Weigand 
575b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
576b9c1b51eSKate Stone     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
577bb00d0b6SUlrich Weigand   per_struct per_info;
578bb00d0b6SUlrich Weigand 
579bb00d0b6SUlrich Weigand   if (watch_flags != 0x1)
580bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
581bb00d0b6SUlrich Weigand 
582bb00d0b6SUlrich Weigand   if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
583bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
584bb00d0b6SUlrich Weigand 
58597206d57SZachary Turner   Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
586b9c1b51eSKate Stone                               sizeof(per_info));
587bb00d0b6SUlrich Weigand   if (error.Fail())
588bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
589bb00d0b6SUlrich Weigand 
590bb00d0b6SUlrich Weigand   per_info.control_regs.bits.em_storage_alteration = 1;
591bb00d0b6SUlrich Weigand   per_info.control_regs.bits.storage_alt_space_ctl = 1;
592bb00d0b6SUlrich Weigand   per_info.starting_addr = addr;
593bb00d0b6SUlrich Weigand   per_info.ending_addr = addr + size - 1;
594bb00d0b6SUlrich Weigand 
595b9c1b51eSKate Stone   error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
596b9c1b51eSKate Stone                        sizeof(per_info));
597bb00d0b6SUlrich Weigand   if (error.Fail())
598bb00d0b6SUlrich Weigand     return LLDB_INVALID_INDEX32;
599bb00d0b6SUlrich Weigand 
600bb00d0b6SUlrich Weigand   m_watchpoint_addr = addr;
601bb00d0b6SUlrich Weigand   return 0;
602bb00d0b6SUlrich Weigand }
603bb00d0b6SUlrich Weigand 
604bb00d0b6SUlrich Weigand lldb::addr_t
605b9c1b51eSKate Stone NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
606bb00d0b6SUlrich Weigand   if (wp_index >= NumSupportedHardwareWatchpoints())
607bb00d0b6SUlrich Weigand     return LLDB_INVALID_ADDRESS;
608bb00d0b6SUlrich Weigand   return m_watchpoint_addr;
609bb00d0b6SUlrich Weigand }
610bb00d0b6SUlrich Weigand 
611b9c1b51eSKate Stone uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
612bb00d0b6SUlrich Weigand   return 1;
613bb00d0b6SUlrich Weigand }
614bb00d0b6SUlrich Weigand 
615bb00d0b6SUlrich Weigand #endif // defined(__s390x__) && defined(__linux__)
616