1 //===-- NativeRegisterContextLinux_s390x.cpp ------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #if defined(__s390x__) && defined(__linux__)
10
11 #include "NativeRegisterContextLinux_s390x.h"
12 #include "Plugins/Process/Linux/NativeProcessLinux.h"
13 #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h"
14 #include "lldb/Host/HostInfo.h"
15 #include "lldb/Utility/DataBufferHeap.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/RegisterValue.h"
18 #include "lldb/Utility/Status.h"
19 #include <sys/ptrace.h>
20 #include <sys/uio.h>
21
22 using namespace lldb_private;
23 using namespace lldb_private::process_linux;
24
25 // Private namespace.
26
27 namespace {
28 // s390x 64-bit general purpose registers.
29 static const uint32_t g_gpr_regnums_s390x[] = {
30 lldb_r0_s390x, lldb_r1_s390x, lldb_r2_s390x, lldb_r3_s390x,
31 lldb_r4_s390x, lldb_r5_s390x, lldb_r6_s390x, lldb_r7_s390x,
32 lldb_r8_s390x, lldb_r9_s390x, lldb_r10_s390x, lldb_r11_s390x,
33 lldb_r12_s390x, lldb_r13_s390x, lldb_r14_s390x, lldb_r15_s390x,
34 lldb_acr0_s390x, lldb_acr1_s390x, lldb_acr2_s390x, lldb_acr3_s390x,
35 lldb_acr4_s390x, lldb_acr5_s390x, lldb_acr6_s390x, lldb_acr7_s390x,
36 lldb_acr8_s390x, lldb_acr9_s390x, lldb_acr10_s390x, lldb_acr11_s390x,
37 lldb_acr12_s390x, lldb_acr13_s390x, lldb_acr14_s390x, lldb_acr15_s390x,
38 lldb_pswm_s390x, lldb_pswa_s390x,
39 LLDB_INVALID_REGNUM // register sets need to end with this flag
40 };
41 static_assert((sizeof(g_gpr_regnums_s390x) / sizeof(g_gpr_regnums_s390x[0])) -
42 1 ==
43 k_num_gpr_registers_s390x,
44 "g_gpr_regnums_s390x has wrong number of register infos");
45
46 // s390x 64-bit floating point registers.
47 static const uint32_t g_fpu_regnums_s390x[] = {
48 lldb_f0_s390x, lldb_f1_s390x, lldb_f2_s390x, lldb_f3_s390x,
49 lldb_f4_s390x, lldb_f5_s390x, lldb_f6_s390x, lldb_f7_s390x,
50 lldb_f8_s390x, lldb_f9_s390x, lldb_f10_s390x, lldb_f11_s390x,
51 lldb_f12_s390x, lldb_f13_s390x, lldb_f14_s390x, lldb_f15_s390x,
52 lldb_fpc_s390x,
53 LLDB_INVALID_REGNUM // register sets need to end with this flag
54 };
55 static_assert((sizeof(g_fpu_regnums_s390x) / sizeof(g_fpu_regnums_s390x[0])) -
56 1 ==
57 k_num_fpr_registers_s390x,
58 "g_fpu_regnums_s390x has wrong number of register infos");
59
60 // s390x Linux operating-system information.
61 static const uint32_t g_linux_regnums_s390x[] = {
62 lldb_orig_r2_s390x, lldb_last_break_s390x, lldb_system_call_s390x,
63 LLDB_INVALID_REGNUM // register sets need to end with this flag
64 };
65 static_assert((sizeof(g_linux_regnums_s390x) /
66 sizeof(g_linux_regnums_s390x[0])) -
67 1 ==
68 k_num_linux_registers_s390x,
69 "g_linux_regnums_s390x has wrong number of register infos");
70
71 // Number of register sets provided by this context.
72 enum { k_num_register_sets = 3 };
73
74 // Register sets for s390x 64-bit.
75 static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = {
76 {"General Purpose Registers", "gpr", k_num_gpr_registers_s390x,
77 g_gpr_regnums_s390x},
78 {"Floating Point Registers", "fpr", k_num_fpr_registers_s390x,
79 g_fpu_regnums_s390x},
80 {"Linux Operating System Data", "linux", k_num_linux_registers_s390x,
81 g_linux_regnums_s390x},
82 };
83 }
84
85 #define REG_CONTEXT_SIZE (sizeof(s390_regs) + sizeof(s390_fp_regs) + 4)
86
87 // Required ptrace defines.
88
89 #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
90 #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
91
92 std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)93 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
94 const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
95 return std::make_unique<NativeRegisterContextLinux_s390x>(target_arch,
96 native_thread);
97 }
98
99 llvm::Expected<ArchSpec>
DetermineArchitecture(lldb::tid_t tid)100 NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
101 return HostInfo::GetArchitecture();
102 }
103
104 // NativeRegisterContextLinux_s390x members.
105
106 static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)107 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
108 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
109 "Register setting path assumes this is a 64-bit host");
110 return new RegisterContextLinux_s390x(target_arch);
111 }
112
NativeRegisterContextLinux_s390x(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)113 NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x(
114 const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
115 : NativeRegisterContextRegisterInfo(
116 native_thread, CreateRegisterInfoInterface(target_arch)),
117 NativeRegisterContextLinux(native_thread) {
118 // Set up data about ranges of valid registers.
119 switch (target_arch.GetMachine()) {
120 case llvm::Triple::systemz:
121 m_reg_info.num_registers = k_num_registers_s390x;
122 m_reg_info.num_gpr_registers = k_num_gpr_registers_s390x;
123 m_reg_info.num_fpr_registers = k_num_fpr_registers_s390x;
124 m_reg_info.last_gpr = k_last_gpr_s390x;
125 m_reg_info.first_fpr = k_first_fpr_s390x;
126 m_reg_info.last_fpr = k_last_fpr_s390x;
127 break;
128 default:
129 assert(false && "Unhandled target architecture.");
130 break;
131 }
132
133 // Clear out the watchpoint state.
134 m_watchpoint_addr = LLDB_INVALID_ADDRESS;
135 }
136
GetRegisterSetCount() const137 uint32_t NativeRegisterContextLinux_s390x::GetRegisterSetCount() const {
138 uint32_t sets = 0;
139 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
140 if (IsRegisterSetAvailable(set_index))
141 ++sets;
142 }
143
144 return sets;
145 }
146
GetUserRegisterCount() const147 uint32_t NativeRegisterContextLinux_s390x::GetUserRegisterCount() const {
148 uint32_t count = 0;
149 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
150 const RegisterSet *set = GetRegisterSet(set_index);
151 if (set)
152 count += set->num_registers;
153 }
154 return count;
155 }
156
157 const RegisterSet *
GetRegisterSet(uint32_t set_index) const158 NativeRegisterContextLinux_s390x::GetRegisterSet(uint32_t set_index) const {
159 if (!IsRegisterSetAvailable(set_index))
160 return nullptr;
161
162 switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
163 case llvm::Triple::systemz:
164 return &g_reg_sets_s390x[set_index];
165 default:
166 assert(false && "Unhandled target architecture.");
167 return nullptr;
168 }
169
170 return nullptr;
171 }
172
IsRegisterSetAvailable(uint32_t set_index) const173 bool NativeRegisterContextLinux_s390x::IsRegisterSetAvailable(
174 uint32_t set_index) const {
175 return set_index < k_num_register_sets;
176 }
177
IsGPR(uint32_t reg_index) const178 bool NativeRegisterContextLinux_s390x::IsGPR(uint32_t reg_index) const {
179 // GPRs come first. "orig_r2" counts as GPR since it is part of the GPR
180 // register area.
181 return reg_index <= m_reg_info.last_gpr || reg_index == lldb_orig_r2_s390x;
182 }
183
IsFPR(uint32_t reg_index) const184 bool NativeRegisterContextLinux_s390x::IsFPR(uint32_t reg_index) const {
185 return (m_reg_info.first_fpr <= reg_index &&
186 reg_index <= m_reg_info.last_fpr);
187 }
188
189 Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)190 NativeRegisterContextLinux_s390x::ReadRegister(const RegisterInfo *reg_info,
191 RegisterValue ®_value) {
192 if (!reg_info)
193 return Status("reg_info NULL");
194
195 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
196 if (reg == LLDB_INVALID_REGNUM)
197 return Status("register \"%s\" is an internal-only lldb register, cannot "
198 "read directly",
199 reg_info->name);
200
201 if (IsGPR(reg)) {
202 Status error = ReadGPR();
203 if (error.Fail())
204 return error;
205
206 uint8_t *src = (uint8_t *)&m_regs + reg_info->byte_offset;
207 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
208 switch (reg_info->byte_size) {
209 case 4:
210 reg_value.SetUInt32(*(uint32_t *)src);
211 break;
212 case 8:
213 reg_value.SetUInt64(*(uint64_t *)src);
214 break;
215 default:
216 assert(false && "Unhandled data size.");
217 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
218 }
219 return Status();
220 }
221
222 if (IsFPR(reg)) {
223 Status error = ReadFPR();
224 if (error.Fail())
225 return error;
226
227 // byte_offset is just the offset within FPR, not the whole user area.
228 uint8_t *src = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
229 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
230 switch (reg_info->byte_size) {
231 case 4:
232 reg_value.SetUInt32(*(uint32_t *)src);
233 break;
234 case 8:
235 reg_value.SetUInt64(*(uint64_t *)src);
236 break;
237 default:
238 assert(false && "Unhandled data size.");
239 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
240 }
241 return Status();
242 }
243
244 if (reg == lldb_last_break_s390x) {
245 uint64_t last_break;
246 Status error = DoReadRegisterSet(NT_S390_LAST_BREAK, &last_break, 8);
247 if (error.Fail())
248 return error;
249
250 reg_value.SetUInt64(last_break);
251 return Status();
252 }
253
254 if (reg == lldb_system_call_s390x) {
255 uint32_t system_call;
256 Status error = DoReadRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
257 if (error.Fail())
258 return error;
259
260 reg_value.SetUInt32(system_call);
261 return Status();
262 }
263
264 return Status("failed - register wasn't recognized");
265 }
266
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)267 Status NativeRegisterContextLinux_s390x::WriteRegister(
268 const RegisterInfo *reg_info, const RegisterValue ®_value) {
269 if (!reg_info)
270 return Status("reg_info NULL");
271
272 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
273 if (reg == LLDB_INVALID_REGNUM)
274 return Status("register \"%s\" is an internal-only lldb register, cannot "
275 "write directly",
276 reg_info->name);
277
278 if (IsGPR(reg)) {
279 Status error = ReadGPR();
280 if (error.Fail())
281 return error;
282
283 uint8_t *dst = (uint8_t *)&m_regs + reg_info->byte_offset;
284 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_regs));
285 switch (reg_info->byte_size) {
286 case 4:
287 *(uint32_t *)dst = reg_value.GetAsUInt32();
288 break;
289 case 8:
290 *(uint64_t *)dst = reg_value.GetAsUInt64();
291 break;
292 default:
293 assert(false && "Unhandled data size.");
294 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
295 }
296 return WriteGPR();
297 }
298
299 if (IsFPR(reg)) {
300 Status error = ReadFPR();
301 if (error.Fail())
302 return error;
303
304 // byte_offset is just the offset within fp_regs, not the whole user area.
305 uint8_t *dst = (uint8_t *)&m_fp_regs + reg_info->byte_offset;
306 assert(reg_info->byte_offset + reg_info->byte_size <= sizeof(m_fp_regs));
307 switch (reg_info->byte_size) {
308 case 4:
309 *(uint32_t *)dst = reg_value.GetAsUInt32();
310 break;
311 case 8:
312 *(uint64_t *)dst = reg_value.GetAsUInt64();
313 break;
314 default:
315 assert(false && "Unhandled data size.");
316 return Status("unhandled byte size: %" PRIu32, reg_info->byte_size);
317 }
318 return WriteFPR();
319 }
320
321 if (reg == lldb_last_break_s390x) {
322 return Status("The last break address is read-only");
323 }
324
325 if (reg == lldb_system_call_s390x) {
326 uint32_t system_call = reg_value.GetAsUInt32();
327 return DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
328 }
329
330 return Status("failed - register wasn't recognized");
331 }
332
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)333 Status NativeRegisterContextLinux_s390x::ReadAllRegisterValues(
334 lldb::WritableDataBufferSP &data_sp) {
335 Status error;
336
337 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
338 uint8_t *dst = data_sp->GetBytes();
339 error = ReadGPR();
340 if (error.Fail())
341 return error;
342 memcpy(dst, GetGPRBuffer(), GetGPRSize());
343 dst += GetGPRSize();
344
345 error = ReadFPR();
346 if (error.Fail())
347 return error;
348 memcpy(dst, GetFPRBuffer(), GetFPRSize());
349 dst += GetFPRSize();
350
351 // Ignore errors if the regset is unsupported (happens on older kernels).
352 DoReadRegisterSet(NT_S390_SYSTEM_CALL, dst, 4);
353 dst += 4;
354
355 // To enable inferior function calls while the process is stopped in an
356 // interrupted system call, we need to clear the system call flag. It will be
357 // restored to its original value by WriteAllRegisterValues. Again we ignore
358 // error if the regset is unsupported.
359 uint32_t system_call = 0;
360 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, &system_call, 4);
361
362 return error;
363 }
364
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)365 Status NativeRegisterContextLinux_s390x::WriteAllRegisterValues(
366 const lldb::DataBufferSP &data_sp) {
367 Status error;
368
369 if (!data_sp) {
370 error.SetErrorStringWithFormat(
371 "NativeRegisterContextLinux_s390x::%s invalid data_sp provided",
372 __FUNCTION__);
373 return error;
374 }
375
376 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
377 error.SetErrorStringWithFormat(
378 "NativeRegisterContextLinux_s390x::%s data_sp contained mismatched "
379 "data size, expected %" PRIu64 ", actual %" PRIu64,
380 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
381 return error;
382 }
383
384 const uint8_t *src = data_sp->GetBytes();
385 if (src == nullptr) {
386 error.SetErrorStringWithFormat("NativeRegisterContextLinux_s390x::%s "
387 "DataBuffer::GetBytes() returned a null "
388 "pointer",
389 __FUNCTION__);
390 return error;
391 }
392
393 memcpy(GetGPRBuffer(), src, GetGPRSize());
394 src += GetGPRSize();
395 error = WriteGPR();
396 if (error.Fail())
397 return error;
398
399 memcpy(GetFPRBuffer(), src, GetFPRSize());
400 src += GetFPRSize();
401 error = WriteFPR();
402 if (error.Fail())
403 return error;
404
405 // Ignore errors if the regset is unsupported (happens on older kernels).
406 DoWriteRegisterSet(NT_S390_SYSTEM_CALL, src, 4);
407 src += 4;
408
409 return error;
410 }
411
DoReadRegisterValue(uint32_t offset,const char * reg_name,uint32_t size,RegisterValue & value)412 Status NativeRegisterContextLinux_s390x::DoReadRegisterValue(
413 uint32_t offset, const char *reg_name, uint32_t size,
414 RegisterValue &value) {
415 return Status("DoReadRegisterValue unsupported");
416 }
417
DoWriteRegisterValue(uint32_t offset,const char * reg_name,const RegisterValue & value)418 Status NativeRegisterContextLinux_s390x::DoWriteRegisterValue(
419 uint32_t offset, const char *reg_name, const RegisterValue &value) {
420 return Status("DoWriteRegisterValue unsupported");
421 }
422
PeekUserArea(uint32_t offset,void * buf,size_t buf_size)423 Status NativeRegisterContextLinux_s390x::PeekUserArea(uint32_t offset,
424 void *buf,
425 size_t buf_size) {
426 ptrace_area parea;
427 parea.len = buf_size;
428 parea.process_addr = (addr_t)buf;
429 parea.kernel_addr = offset;
430
431 return NativeProcessLinux::PtraceWrapper(PTRACE_PEEKUSR_AREA,
432 m_thread.GetID(), &parea);
433 }
434
PokeUserArea(uint32_t offset,const void * buf,size_t buf_size)435 Status NativeRegisterContextLinux_s390x::PokeUserArea(uint32_t offset,
436 const void *buf,
437 size_t buf_size) {
438 ptrace_area parea;
439 parea.len = buf_size;
440 parea.process_addr = (addr_t)buf;
441 parea.kernel_addr = offset;
442
443 return NativeProcessLinux::PtraceWrapper(PTRACE_POKEUSR_AREA,
444 m_thread.GetID(), &parea);
445 }
446
ReadGPR()447 Status NativeRegisterContextLinux_s390x::ReadGPR() {
448 return PeekUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
449 GetGPRSize());
450 }
451
WriteGPR()452 Status NativeRegisterContextLinux_s390x::WriteGPR() {
453 return PokeUserArea(offsetof(user_regs_struct, psw), GetGPRBuffer(),
454 GetGPRSize());
455 }
456
ReadFPR()457 Status NativeRegisterContextLinux_s390x::ReadFPR() {
458 return PeekUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
459 GetGPRSize());
460 }
461
WriteFPR()462 Status NativeRegisterContextLinux_s390x::WriteFPR() {
463 return PokeUserArea(offsetof(user_regs_struct, fp_regs), GetGPRBuffer(),
464 GetGPRSize());
465 }
466
DoReadRegisterSet(uint32_t regset,void * buf,size_t buf_size)467 Status NativeRegisterContextLinux_s390x::DoReadRegisterSet(uint32_t regset,
468 void *buf,
469 size_t buf_size) {
470 struct iovec iov;
471 iov.iov_base = buf;
472 iov.iov_len = buf_size;
473
474 return ReadRegisterSet(&iov, buf_size, regset);
475 }
476
DoWriteRegisterSet(uint32_t regset,const void * buf,size_t buf_size)477 Status NativeRegisterContextLinux_s390x::DoWriteRegisterSet(uint32_t regset,
478 const void *buf,
479 size_t buf_size) {
480 struct iovec iov;
481 iov.iov_base = const_cast<void *>(buf);
482 iov.iov_len = buf_size;
483
484 return WriteRegisterSet(&iov, buf_size, regset);
485 }
486
IsWatchpointHit(uint32_t wp_index,bool & is_hit)487 Status NativeRegisterContextLinux_s390x::IsWatchpointHit(uint32_t wp_index,
488 bool &is_hit) {
489 per_lowcore_bits per_lowcore;
490
491 if (wp_index >= NumSupportedHardwareWatchpoints())
492 return Status("Watchpoint index out of range");
493
494 if (m_watchpoint_addr == LLDB_INVALID_ADDRESS) {
495 is_hit = false;
496 return Status();
497 }
498
499 Status error = PeekUserArea(offsetof(user_regs_struct, per_info.lowcore),
500 &per_lowcore, sizeof(per_lowcore));
501 if (error.Fail()) {
502 is_hit = false;
503 return error;
504 }
505
506 is_hit = (per_lowcore.perc_storage_alteration == 1 &&
507 per_lowcore.perc_store_real_address == 0);
508
509 if (is_hit) {
510 // Do not report this watchpoint again.
511 memset(&per_lowcore, 0, sizeof(per_lowcore));
512 PokeUserArea(offsetof(user_regs_struct, per_info.lowcore), &per_lowcore,
513 sizeof(per_lowcore));
514 }
515
516 return Status();
517 }
518
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)519 Status NativeRegisterContextLinux_s390x::GetWatchpointHitIndex(
520 uint32_t &wp_index, lldb::addr_t trap_addr) {
521 uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
522 for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
523 bool is_hit;
524 Status error = IsWatchpointHit(wp_index, is_hit);
525 if (error.Fail()) {
526 wp_index = LLDB_INVALID_INDEX32;
527 return error;
528 } else if (is_hit) {
529 return error;
530 }
531 }
532 wp_index = LLDB_INVALID_INDEX32;
533 return Status();
534 }
535
IsWatchpointVacant(uint32_t wp_index,bool & is_vacant)536 Status NativeRegisterContextLinux_s390x::IsWatchpointVacant(uint32_t wp_index,
537 bool &is_vacant) {
538 if (wp_index >= NumSupportedHardwareWatchpoints())
539 return Status("Watchpoint index out of range");
540
541 is_vacant = m_watchpoint_addr == LLDB_INVALID_ADDRESS;
542
543 return Status();
544 }
545
ClearHardwareWatchpoint(uint32_t wp_index)546 bool NativeRegisterContextLinux_s390x::ClearHardwareWatchpoint(
547 uint32_t wp_index) {
548 per_struct per_info;
549
550 if (wp_index >= NumSupportedHardwareWatchpoints())
551 return false;
552
553 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
554 sizeof(per_info));
555 if (error.Fail())
556 return false;
557
558 per_info.control_regs.bits.em_storage_alteration = 0;
559 per_info.control_regs.bits.storage_alt_space_ctl = 0;
560 per_info.starting_addr = 0;
561 per_info.ending_addr = 0;
562
563 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
564 sizeof(per_info));
565 if (error.Fail())
566 return false;
567
568 m_watchpoint_addr = LLDB_INVALID_ADDRESS;
569 return true;
570 }
571
ClearAllHardwareWatchpoints()572 Status NativeRegisterContextLinux_s390x::ClearAllHardwareWatchpoints() {
573 if (ClearHardwareWatchpoint(0))
574 return Status();
575 return Status("Clearing all hardware watchpoints failed.");
576 }
577
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)578 uint32_t NativeRegisterContextLinux_s390x::SetHardwareWatchpoint(
579 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
580 per_struct per_info;
581
582 if (watch_flags != 0x1)
583 return LLDB_INVALID_INDEX32;
584
585 if (m_watchpoint_addr != LLDB_INVALID_ADDRESS)
586 return LLDB_INVALID_INDEX32;
587
588 Status error = PeekUserArea(offsetof(user_regs_struct, per_info), &per_info,
589 sizeof(per_info));
590 if (error.Fail())
591 return LLDB_INVALID_INDEX32;
592
593 per_info.control_regs.bits.em_storage_alteration = 1;
594 per_info.control_regs.bits.storage_alt_space_ctl = 1;
595 per_info.starting_addr = addr;
596 per_info.ending_addr = addr + size - 1;
597
598 error = PokeUserArea(offsetof(user_regs_struct, per_info), &per_info,
599 sizeof(per_info));
600 if (error.Fail())
601 return LLDB_INVALID_INDEX32;
602
603 m_watchpoint_addr = addr;
604 return 0;
605 }
606
607 lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)608 NativeRegisterContextLinux_s390x::GetWatchpointAddress(uint32_t wp_index) {
609 if (wp_index >= NumSupportedHardwareWatchpoints())
610 return LLDB_INVALID_ADDRESS;
611 return m_watchpoint_addr;
612 }
613
NumSupportedHardwareWatchpoints()614 uint32_t NativeRegisterContextLinux_s390x::NumSupportedHardwareWatchpoints() {
615 return 1;
616 }
617
618 #endif // defined(__s390x__) && defined(__linux__)
619