1dda28197Spatrick //===-- NativeRegisterContextLinux_s390x.cpp ------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #if defined(__s390x__) && defined(__linux__)
10061da546Spatrick
11061da546Spatrick #include "NativeRegisterContextLinux_s390x.h"
12061da546Spatrick #include "Plugins/Process/Linux/NativeProcessLinux.h"
13*f6aab3d8Srobert #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
14061da546Spatrick #include "lldb/Host/HostInfo.h"
15061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
16061da546Spatrick #include "lldb/Utility/Log.h"
17061da546Spatrick #include "lldb/Utility/RegisterValue.h"
18061da546Spatrick #include "lldb/Utility/Status.h"
19061da546Spatrick #include <sys/ptrace.h>
20*f6aab3d8Srobert #include <sys/uio.h>
21061da546Spatrick
22061da546Spatrick using namespace lldb_private;
23061da546Spatrick using namespace lldb_private::process_linux;
24061da546Spatrick
25061da546Spatrick // Private namespace.
26061da546Spatrick
27061da546Spatrick namespace {
28061da546Spatrick // s390x 64-bit general purpose registers.
29061da546Spatrick static const uint32_t g_gpr_regnums_s390x[] = {
30061da546Spatrick lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x,
31061da546Spatrick lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x,
32061da546Spatrick lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x,
33061da546Spatrick lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x,
34061da546Spatrick lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x,
35061da546Spatrick lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x,
36061da546Spatrick lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x,
37061da546Spatrick lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
38061da546Spatrick lldb_pswm_s390x, lldb_pswa_s390x,
39061da546Spatrick LLDB_INVALID_REGNUM // register sets need to end with this flag
40061da546Spatrick };
41061da546Spatrick static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
42061da546Spatrick 1 ==
43061da546Spatrick k_num_gpr_registers_s390x,
44061da546Spatrick "g_gpr_regnums_s390x has wrong number of register infos");
45061da546Spatrick
46061da546Spatrick // s390x 64-bit floating point registers.
47061da546Spatrick static const uint32_t g_fpu_regnums_s390x[] = {
48061da546Spatrick lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x,
49061da546Spatrick lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x,
50061da546Spatrick lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x,
51061da546Spatrick lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
52061da546Spatrick lldb_fpc_s390x,
53061da546Spatrick LLDB_INVALID_REGNUM // register sets need to end with this flag
54061da546Spatrick };
55061da546Spatrick static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
56061da546Spatrick 1 ==
57061da546Spatrick k_num_fpr_registers_s390x,
58061da546Spatrick "g_fpu_regnums_s390x has wrong number of register infos");
59061da546Spatrick
60061da546Spatrick // s390x Linux operating-system information.
61061da546Spatrick static const uint32_t g_linux_regnums_s390x[] = {
62061da546Spatrick lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x,
63061da546Spatrick LLDB_INVALID_REGNUM // register sets need to end with this flag
64061da546Spatrick };
65061da546Spatrick static_assert((sizeof(g_linux_regnums_s390x) /
66061da546Spatrick sizeof(g_linux_regnums_s390x[0])) -
67061da546Spatrick 1 ==
68061da546Spatrick k_num_linux_registers_s390x,
69061da546Spatrick "g_linux_regnums_s390x has wrong number of register infos");
70061da546Spatrick
71061da546Spatrick // Number of register sets provided by this context.
72061da546Spatrick enum { k_num_register_sets = 3 };
73061da546Spatrick
74061da546Spatrick // Register sets for s390x 64-bit.
75061da546Spatrick static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
76061da546Spatrick {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
77061da546Spatrick g_gpr_regnums_s390x},
78061da546Spatrick {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
79061da546Spatrick g_fpu_regnums_s390x},
80061da546Spatrick {"Linux Operating System Data", "linux", k_num_linux_registers_s390x,
81061da546Spatrick g_linux_regnums_s390x},
82061da546Spatrick };
83061da546Spatrick }
84061da546Spatrick
85061da546Spatrick #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4)
86061da546Spatrick
87061da546Spatrick // Required ptrace defines.
88061da546Spatrick
89061da546Spatrick #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
90061da546Spatrick #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
91061da546Spatrick
92061da546Spatrick std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)93061da546Spatrick NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
94be691f3bSpatrick const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
95061da546Spatrick return std::make_unique<NativeRegisterContextLinux_s390x>(target_arch,
96061da546Spatrick native_thread);
97061da546Spatrick }
98061da546Spatrick
99*f6aab3d8Srobert llvm::Expected<ArchSpec>
DetermineArchitecture(lldb::tid_t tid)100*f6aab3d8Srobert NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
101*f6aab3d8Srobert return HostInfo::GetArchitecture();
102*f6aab3d8Srobert }
103*f6aab3d8Srobert
104061da546Spatrick // NativeRegisterContextLinux_s390x members.
105061da546Spatrick
106061da546Spatrick static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)107061da546Spatrick CreateRegisterInfoInterface(const ArchSpec &target_arch) {
108061da546Spatrick assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
109061da546Spatrick "Register setting path assumes this is a 64-bit host");
110061da546Spatrick return new RegisterContextLinux_s390x(target_arch);
111061da546Spatrick }
112061da546Spatrick
NativeRegisterContextLinux_s390x(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)113061da546Spatrick NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(
114061da546Spatrick const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
115be691f3bSpatrick : NativeRegisterContextRegisterInfo(
116be691f3bSpatrick native_thread, CreateRegisterInfoInterface(target_arch)),
117be691f3bSpatrick NativeRegisterContextLinux(native_thread) {
118061da546Spatrick // Set up data about ranges of valid registers.
119061da546Spatrick switch (target_arch.GetMachine()) {
120061da546Spatrick case llvm::Triple::systemz:
121061da546Spatrick m_reg_info.num_registers = k_num_registers_s390x;
122061da546Spatrick m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
123061da546Spatrick m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
124061da546Spatrick m_reg_info.last_gpr = k_last_gpr_s390x;
125061da546Spatrick m_reg_info.first_fpr = k_first_fpr_s390x;
126061da546Spatrick m_reg_info.last_fpr = k_last_fpr_s390x;
127061da546Spatrick break;
128061da546Spatrick default:
129061da546Spatrick assert(false && "Unhandled target architecture.");
130061da546Spatrick break;
131061da546Spatrick }
132061da546Spatrick
133061da546Spatrick // Clear out the watchpoint state.
134061da546Spatrick m_watchpoint_addr = LLDB_INVALID_ADDRESS;
135061da546Spatrick }
136061da546Spatrick
GetRegisterSetCount() const137061da546Spatrick uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
138061da546Spatrick uint32_t sets = 0;
139061da546Spatrick for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
140061da546Spatrick if (IsRegisterSetAvailable(set_index))
141061da546Spatrick ++sets;
142061da546Spatrick }
143061da546Spatrick
144061da546Spatrick return sets;
145061da546Spatrick }
146061da546Spatrick
GetUserRegisterCount() const147061da546Spatrick uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
148061da546Spatrick uint32_t count = 0;
149061da546Spatrick for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
150061da546Spatrick const RegisterSet *set = GetRegisterSet(set_index);
151061da546Spatrick if (set)
152061da546Spatrick count += set->num_registers;
153061da546Spatrick }
154061da546Spatrick return count;
155061da546Spatrick }
156061da546Spatrick
157061da546Spatrick const RegisterSet *
GetRegisterSet(uint32_t set_index) const158061da546Spatrick NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
159061da546Spatrick if (!IsRegisterSetAvailable(set_index))
160061da546Spatrick return nullptr;
161061da546Spatrick
162061da546Spatrick switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
163061da546Spatrick case llvm::Triple::systemz:
164061da546Spatrick return &g_reg_sets_s390x[set_index];
165061da546Spatrick default:
166061da546Spatrick assert(false && "Unhandled target architecture.");
167061da546Spatrick return nullptr;
168061da546Spatrick }
169061da546Spatrick
170061da546Spatrick return nullptr;
171061da546Spatrick }
172061da546Spatrick
IsRegisterSetAvailable(uint32_t set_index) const173061da546Spatrick bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
174061da546Spatrick uint32_t set_index) const {
175061da546Spatrick return set_index < k_num_register_sets;
176061da546Spatrick }
177061da546Spatrick
IsGPR(uint32_t reg_index) const178061da546Spatrick bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
179061da546Spatrick // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR
180061da546Spatrick // register area.
181061da546Spatrick return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
182061da546Spatrick }
183061da546Spatrick
IsFPR(uint32_t reg_index) const184061da546Spatrick bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
185061da546Spatrick return (m_reg_info.first_fpr <= reg_index &&
186061da546Spatrick reg_index <= m_reg_info.last_fpr);
187061da546Spatrick }
188061da546Spatrick
189061da546Spatrick Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)190061da546Spatrick NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info,
191061da546Spatrick RegisterValue ®_value) {
192061da546Spatrick if (!reg_info)
193061da546Spatrick return Status("reg_info NULL");
194061da546Spatrick
195061da546Spatrick const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
196061da546Spatrick if (reg == LLDB_INVALID_REGNUM)
197061da546Spatrick return Status("register \"%s\" is an internal-only lldb register, cannot "
198061da546Spatrick "read directly",
199061da546Spatrick reg_info->name);
200061da546Spatrick
201061da546Spatrick if (IsGPR(reg)) {
202061da546Spatrick Status error = ReadGPR();
203061da546Spatrick if (error.Fail())
204061da546Spatrick return error;
205061da546Spatrick
206061da546Spatrick uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset;
207061da546Spatrick assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
208061da546Spatrick switch (reg_info->byte_size) {
209061da546Spatrick case 4:
210061da546Spatrick reg_value.SetUInt32(*(uint32_t *)src);
211061da546Spatrick break;
212061da546Spatrick case 8:
213061da546Spatrick reg_value.SetUInt64(*(uint64_t *)src);
214061da546Spatrick break;
215061da546Spatrick default:
216061da546Spatrick assert(false && "Unhandled data size.");
217061da546Spatrick return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
218061da546Spatrick }
219061da546Spatrick return Status();
220061da546Spatrick }
221061da546Spatrick
222061da546Spatrick if (IsFPR(reg)) {
223061da546Spatrick Status error = ReadFPR();
224061da546Spatrick if (error.Fail())
225061da546Spatrick return error;
226061da546Spatrick
227061da546Spatrick // byte_offset is just the offset within FPR, not the whole user area.
228061da546Spatrick uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
229061da546Spatrick assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
230061da546Spatrick switch (reg_info->byte_size) {
231061da546Spatrick case 4:
232061da546Spatrick reg_value.SetUInt32(*(uint32_t *)src);
233061da546Spatrick break;
234061da546Spatrick case 8:
235061da546Spatrick reg_value.SetUInt64(*(uint64_t *)src);
236061da546Spatrick break;
237061da546Spatrick default:
238061da546Spatrick assert(false && "Unhandled data size.");
239061da546Spatrick return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
240061da546Spatrick }
241061da546Spatrick return Status();
242061da546Spatrick }
243061da546Spatrick
244061da546Spatrick if (reg == lldb_last_break_s390x) {
245061da546Spatrick uint64_t last_break;
246061da546Spatrick Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
247061da546Spatrick if (error.Fail())
248061da546Spatrick return error;
249061da546Spatrick
250061da546Spatrick reg_value.SetUInt64(last_break);
251061da546Spatrick return Status();
252061da546Spatrick }
253061da546Spatrick
254061da546Spatrick if (reg == lldb_system_call_s390x) {
255061da546Spatrick uint32_t system_call;
256061da546Spatrick Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
257061da546Spatrick if (error.Fail())
258061da546Spatrick return error;
259061da546Spatrick
260061da546Spatrick reg_value.SetUInt32(system_call);
261061da546Spatrick return Status();
262061da546Spatrick }
263061da546Spatrick
264061da546Spatrick return Status("failed - register wasn't recognized");
265061da546Spatrick }
266061da546Spatrick
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)267061da546Spatrick Status NativeRegisterContextLinux_s390x::WriteRegister(
268061da546Spatrick const RegisterInfo *reg_info, const RegisterValue ®_value) {
269061da546Spatrick if (!reg_info)
270061da546Spatrick return Status("reg_info NULL");
271061da546Spatrick
272061da546Spatrick const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
273061da546Spatrick if (reg == LLDB_INVALID_REGNUM)
274061da546Spatrick return Status("register \"%s\" is an internal-only lldb register, cannot "
275061da546Spatrick "write directly",
276061da546Spatrick reg_info->name);
277061da546Spatrick
278061da546Spatrick if (IsGPR(reg)) {
279061da546Spatrick Status error = ReadGPR();
280061da546Spatrick if (error.Fail())
281061da546Spatrick return error;
282061da546Spatrick
283061da546Spatrick uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset;
284061da546Spatrick assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
285061da546Spatrick switch (reg_info->byte_size) {
286061da546Spatrick case 4:
287061da546Spatrick *(uint32_t *)dst = reg_value.GetAsUInt32();
288061da546Spatrick break;
289061da546Spatrick case 8:
290061da546Spatrick *(uint64_t *)dst = reg_value.GetAsUInt64();
291061da546Spatrick break;
292061da546Spatrick default:
293061da546Spatrick assert(false && "Unhandled data size.");
294061da546Spatrick return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
295061da546Spatrick }
296061da546Spatrick return WriteGPR();
297061da546Spatrick }
298061da546Spatrick
299061da546Spatrick if (IsFPR(reg)) {
300061da546Spatrick Status error = ReadFPR();
301061da546Spatrick if (error.Fail())
302061da546Spatrick return error;
303061da546Spatrick
304061da546Spatrick // byte_offset is just the offset within fp_regs, not the whole user area.
305061da546Spatrick uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
306061da546Spatrick assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
307061da546Spatrick switch (reg_info->byte_size) {
308061da546Spatrick case 4:
309061da546Spatrick *(uint32_t *)dst = reg_value.GetAsUInt32();
310061da546Spatrick break;
311061da546Spatrick case 8:
312061da546Spatrick *(uint64_t *)dst = reg_value.GetAsUInt64();
313061da546Spatrick break;
314061da546Spatrick default:
315061da546Spatrick assert(false && "Unhandled data size.");
316061da546Spatrick return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
317061da546Spatrick }
318061da546Spatrick return WriteFPR();
319061da546Spatrick }
320061da546Spatrick
321061da546Spatrick if (reg == lldb_last_break_s390x) {
322061da546Spatrick return Status("The last break address is read-only");
323061da546Spatrick }
324061da546Spatrick
325061da546Spatrick if (reg == lldb_system_call_s390x) {
326061da546Spatrick uint32_t system_call = reg_value.GetAsUInt32();
327061da546Spatrick return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
328061da546Spatrick }
329061da546Spatrick
330061da546Spatrick return Status("failed - register wasn't recognized");
331061da546Spatrick }
332061da546Spatrick
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)333061da546Spatrick Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
334*f6aab3d8Srobert lldb::WritableDataBufferSP &data_sp) {
335061da546Spatrick Status error;
336061da546Spatrick
337061da546Spatrick data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
338061da546Spatrick uint8_t *dst = data_sp->GetBytes();
339061da546Spatrick error = ReadGPR();
340061da546Spatrick if (error.Fail())
341061da546Spatrick return error;
342061da546Spatrick memcpy(dst, GetGPRBuffer(), GetGPRSize());
343061da546Spatrick dst += GetGPRSize();
344061da546Spatrick
345061da546Spatrick error = ReadFPR();
346061da546Spatrick if (error.Fail())
347061da546Spatrick return error;
348061da546Spatrick memcpy(dst, GetFPRBuffer(), GetFPRSize());
349061da546Spatrick dst += GetFPRSize();
350061da546Spatrick
351061da546Spatrick // Ignore errors if the regset is unsupported (happens on older kernels).
352061da546Spatrick DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
353061da546Spatrick dst += 4;
354061da546Spatrick
355061da546Spatrick // To enable inferior function calls while the process is stopped in an
356061da546Spatrick // interrupted system call, we need to clear the system call flag. It will be
357061da546Spatrick // restored to its original value by WriteAllRegisterValues. Again we ignore
358061da546Spatrick // error if the regset is unsupported.
359061da546Spatrick uint32_t system_call = 0;
360061da546Spatrick DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
361061da546Spatrick
362061da546Spatrick return error;
363061da546Spatrick }
364061da546Spatrick
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)365061da546Spatrick Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
366061da546Spatrick const lldb::DataBufferSP &data_sp) {
367061da546Spatrick Status error;
368061da546Spatrick
369061da546Spatrick if (!data_sp) {
370061da546Spatrick error.SetErrorStringWithFormat(
371061da546Spatrick "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
372061da546Spatrick __FUNCTION__);
373061da546Spatrick return error;
374061da546Spatrick }
375061da546Spatrick
376061da546Spatrick if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
377061da546Spatrick error.SetErrorStringWithFormat(
378061da546Spatrick "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
379061da546Spatrick "data size, expected %" PRIu64 ", actual %" PRIu64,
380061da546Spatrick __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
381061da546Spatrick return error;
382061da546Spatrick }
383061da546Spatrick
384061da546Spatrick const uint8_t *src = data_sp->GetBytes();
385061da546Spatrick if (src == nullptr) {
386061da546Spatrick error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
387061da546Spatrick "DataBuffer::GetBytes() returned a null "
388061da546Spatrick "pointer",
389061da546Spatrick __FUNCTION__);
390061da546Spatrick return error;
391061da546Spatrick }
392061da546Spatrick
393061da546Spatrick memcpy(GetGPRBuffer(), src, GetGPRSize());
394061da546Spatrick src += GetGPRSize();
395061da546Spatrick error = WriteGPR();
396061da546Spatrick if (error.Fail())
397061da546Spatrick return error;
398061da546Spatrick
399061da546Spatrick memcpy(GetFPRBuffer(), src, GetFPRSize());
400061da546Spatrick src += GetFPRSize();
401061da546Spatrick error = WriteFPR();
402061da546Spatrick if (error.Fail())
403061da546Spatrick return error;
404061da546Spatrick
405061da546Spatrick // Ignore errors if the regset is unsupported (happens on older kernels).
406061da546Spatrick DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
407061da546Spatrick src += 4;
408061da546Spatrick
409061da546Spatrick return error;
410061da546Spatrick }
411061da546Spatrick
DoReadRegisterValue(uint32_t offset,const char * reg_name,uint32_t size,RegisterValue & value)412061da546Spatrick Status NativeRegisterContextLinux_s390x::DoReadRegisterValue(
413061da546Spatrick uint32_t offset, const char *reg_name, uint32_t size,
414061da546Spatrick RegisterValue &value) {
415061da546Spatrick return Status("DoReadRegisterValue unsupported");
416061da546Spatrick }
417061da546Spatrick
DoWriteRegisterValue(uint32_t offset,const char * reg_name,const RegisterValue & value)418061da546Spatrick Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
419061da546Spatrick uint32_t offset, const char *reg_name, const RegisterValue &value) {
420061da546Spatrick return Status("DoWriteRegisterValue unsupported");
421061da546Spatrick }
422061da546Spatrick
PeekUserArea(uint32_t offset,void * buf,size_t buf_size)423061da546Spatrick Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset,
424061da546Spatrick void *buf,
425061da546Spatrick size_t buf_size) {
426061da546Spatrick ptrace_area parea;
427061da546Spatrick parea.len = buf_size;
428061da546Spatrick parea.process_addr = (addr_t)buf;
429061da546Spatrick parea.kernel_addr = offset;
430061da546Spatrick
431061da546Spatrick return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
432061da546Spatrick m_thread.GetID(), &parea);
433061da546Spatrick }
434061da546Spatrick
PokeUserArea(uint32_t offset,const void * buf,size_t buf_size)435061da546Spatrick Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
436061da546Spatrick const void *buf,
437061da546Spatrick size_t buf_size) {
438061da546Spatrick ptrace_area parea;
439061da546Spatrick parea.len = buf_size;
440061da546Spatrick parea.process_addr = (addr_t)buf;
441061da546Spatrick parea.kernel_addr = offset;
442061da546Spatrick
443061da546Spatrick return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
444061da546Spatrick m_thread.GetID(), &parea);
445061da546Spatrick }
446061da546Spatrick
ReadGPR()447061da546Spatrick Status NativeRegisterContextLinux_s390x::ReadGPR() {
448061da546Spatrick return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
449061da546Spatrick GetGPRSize());
450061da546Spatrick }
451061da546Spatrick
WriteGPR()452061da546Spatrick Status NativeRegisterContextLinux_s390x::WriteGPR() {
453061da546Spatrick return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
454061da546Spatrick GetGPRSize());
455061da546Spatrick }
456061da546Spatrick
ReadFPR()457061da546Spatrick Status NativeRegisterContextLinux_s390x::ReadFPR() {
458061da546Spatrick return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
459061da546Spatrick GetGPRSize());
460061da546Spatrick }
461061da546Spatrick
WriteFPR()462061da546Spatrick Status NativeRegisterContextLinux_s390x::WriteFPR() {
463061da546Spatrick return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
464061da546Spatrick GetGPRSize());
465061da546Spatrick }
466061da546Spatrick
DoReadRegisterSet(uint32_t regset,void * buf,size_t buf_size)467061da546Spatrick Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
468061da546Spatrick void *buf,
469061da546Spatrick size_t buf_size) {
470061da546Spatrick struct iovec iov;
471061da546Spatrick iov.iov_base = buf;
472061da546Spatrick iov.iov_len = buf_size;
473061da546Spatrick
474061da546Spatrick return ReadRegisterSet(&iov, buf_size, regset);
475061da546Spatrick }
476061da546Spatrick
DoWriteRegisterSet(uint32_t regset,const void * buf,size_t buf_size)477061da546Spatrick Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
478061da546Spatrick const void *buf,
479061da546Spatrick size_t buf_size) {
480061da546Spatrick struct iovec iov;
481061da546Spatrick iov.iov_base = const_cast<void *>(buf);
482061da546Spatrick iov.iov_len = buf_size;
483061da546Spatrick
484061da546Spatrick return WriteRegisterSet(&iov, buf_size, regset);
485061da546Spatrick }
486061da546Spatrick
IsWatchpointHit(uint32_t wp_index,bool & is_hit)487061da546Spatrick Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
488061da546Spatrick bool &is_hit) {
489061da546Spatrick per_lowcore_bits per_lowcore;
490061da546Spatrick
491061da546Spatrick if (wp_index >= NumSupportedHardwareWatchpoints())
492061da546Spatrick return Status("Watchpoint index out of range");
493061da546Spatrick
494061da546Spatrick if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
495061da546Spatrick is_hit = false;
496061da546Spatrick return Status();
497061da546Spatrick }
498061da546Spatrick
499061da546Spatrick Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
500061da546Spatrick &per_lowcore, sizeof(per_lowcore));
501061da546Spatrick if (error.Fail()) {
502061da546Spatrick is_hit = false;
503061da546Spatrick return error;
504061da546Spatrick }
505061da546Spatrick
506061da546Spatrick is_hit = (per_lowcore.perc_storage_alteration == 1 &&
507061da546Spatrick per_lowcore.perc_store_real_address == 0);
508061da546Spatrick
509061da546Spatrick if (is_hit) {
510061da546Spatrick // Do not report this watchpoint again.
511061da546Spatrick memset(&per_lowcore, 0, sizeof(per_lowcore));
512061da546Spatrick PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
513061da546Spatrick sizeof(per_lowcore));
514061da546Spatrick }
515061da546Spatrick
516061da546Spatrick return Status();
517061da546Spatrick }
518061da546Spatrick
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)519061da546Spatrick Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
520061da546Spatrick uint32_t &wp_index, lldb::addr_t trap_addr) {
521061da546Spatrick uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
522061da546Spatrick for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
523061da546Spatrick bool is_hit;
524061da546Spatrick Status error = IsWatchpointHit(wp_index, is_hit);
525061da546Spatrick if (error.Fail()) {
526061da546Spatrick wp_index = LLDB_INVALID_INDEX32;
527061da546Spatrick return error;
528061da546Spatrick } else if (is_hit) {
529061da546Spatrick return error;
530061da546Spatrick }
531061da546Spatrick }
532061da546Spatrick wp_index = LLDB_INVALID_INDEX32;
533061da546Spatrick return Status();
534061da546Spatrick }
535061da546Spatrick
IsWatchpointVacant(uint32_t wp_index,bool & is_vacant)536061da546Spatrick Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
537061da546Spatrick bool &is_vacant) {
538061da546Spatrick if (wp_index >= NumSupportedHardwareWatchpoints())
539061da546Spatrick return Status("Watchpoint index out of range");
540061da546Spatrick
541061da546Spatrick is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
542061da546Spatrick
543061da546Spatrick return Status();
544061da546Spatrick }
545061da546Spatrick
ClearHardwareWatchpoint(uint32_t wp_index)546061da546Spatrick bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
547061da546Spatrick uint32_t wp_index) {
548061da546Spatrick per_struct per_info;
549061da546Spatrick
550061da546Spatrick if (wp_index >= NumSupportedHardwareWatchpoints())
551061da546Spatrick return false;
552061da546Spatrick
553061da546Spatrick Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
554061da546Spatrick sizeof(per_info));
555061da546Spatrick if (error.Fail())
556061da546Spatrick return false;
557061da546Spatrick
558061da546Spatrick per_info.control_regs.bits.em_storage_alteration = 0;
559061da546Spatrick per_info.control_regs.bits.storage_alt_space_ctl = 0;
560061da546Spatrick per_info.starting_addr = 0;
561061da546Spatrick per_info.ending_addr = 0;
562061da546Spatrick
563061da546Spatrick error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
564061da546Spatrick sizeof(per_info));
565061da546Spatrick if (error.Fail())
566061da546Spatrick return false;
567061da546Spatrick
568061da546Spatrick m_watchpoint_addr = LLDB_INVALID_ADDRESS;
569061da546Spatrick return true;
570061da546Spatrick }
571061da546Spatrick
ClearAllHardwareWatchpoints()572061da546Spatrick Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
573061da546Spatrick if (ClearHardwareWatchpoint(0))
574061da546Spatrick return Status();
575061da546Spatrick return Status("Clearing all hardware watchpoints failed.");
576061da546Spatrick }
577061da546Spatrick
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)578061da546Spatrick uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
579061da546Spatrick lldb::addr_t addr, size_t size, uint32_t watch_flags) {
580061da546Spatrick per_struct per_info;
581061da546Spatrick
582061da546Spatrick if (watch_flags != 0x1)
583061da546Spatrick return LLDB_INVALID_INDEX32;
584061da546Spatrick
585061da546Spatrick if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
586061da546Spatrick return LLDB_INVALID_INDEX32;
587061da546Spatrick
588061da546Spatrick Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
589061da546Spatrick sizeof(per_info));
590061da546Spatrick if (error.Fail())
591061da546Spatrick return LLDB_INVALID_INDEX32;
592061da546Spatrick
593061da546Spatrick per_info.control_regs.bits.em_storage_alteration = 1;
594061da546Spatrick per_info.control_regs.bits.storage_alt_space_ctl = 1;
595061da546Spatrick per_info.starting_addr = addr;
596061da546Spatrick per_info.ending_addr = addr + size - 1;
597061da546Spatrick
598061da546Spatrick error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
599061da546Spatrick sizeof(per_info));
600061da546Spatrick if (error.Fail())
601061da546Spatrick return LLDB_INVALID_INDEX32;
602061da546Spatrick
603061da546Spatrick m_watchpoint_addr = addr;
604061da546Spatrick return 0;
605061da546Spatrick }
606061da546Spatrick
607061da546Spatrick lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)608061da546Spatrick NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
609061da546Spatrick if (wp_index >= NumSupportedHardwareWatchpoints())
610061da546Spatrick return LLDB_INVALID_ADDRESS;
611061da546Spatrick return m_watchpoint_addr;
612061da546Spatrick }
613061da546Spatrick
NumSupportedHardwareWatchpoints()614061da546Spatrick uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
615061da546Spatrick return 1;
616061da546Spatrick }
617061da546Spatrick
618061da546Spatrick #endif // defined(__s390x__) && defined(__linux__)
619