1//===-- NativeRegisterContextLinux_arm.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(__arm__) || defined(__arm64__) || defined(__aarch64__)
10
11#include "NativeRegisterContextLinux_arm.h"
12
13#include "Plugins/Process/Linux/NativeProcessLinux.h"
14#include "Plugins/Process/Linux/Procfs.h"
15#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
17#include "lldb/Host/HostInfo.h"
18#include "lldb/Utility/DataBufferHeap.h"
19#include "lldb/Utility/Log.h"
20#include "lldb/Utility/RegisterValue.h"
21#include "lldb/Utility/Status.h"
22
23#include <elf.h>
24#include <sys/uio.h>
25
26#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
27
28#ifndef PTRACE_GETVFPREGS
29#define PTRACE_GETVFPREGS 27
30#define PTRACE_SETVFPREGS 28
31#endif
32#ifndef PTRACE_GETHBPREGS
33#define PTRACE_GETHBPREGS 29
34#define PTRACE_SETHBPREGS 30
35#endif
36#if !defined(PTRACE_TYPE_ARG3)
37#define PTRACE_TYPE_ARG3 void *
38#endif
39#if !defined(PTRACE_TYPE_ARG4)
40#define PTRACE_TYPE_ARG4 void *
41#endif
42
43using namespace lldb;
44using namespace lldb_private;
45using namespace lldb_private::process_linux;
46
47#if defined(__arm__)
48
49std::unique_ptr<NativeRegisterContextLinux>
50NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
51 const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
52 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
53 native_thread);
54}
55
56llvm::Expected<ArchSpec>
57NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
58 return HostInfo::GetArchitecture();
59}
60
61#endif // defined(__arm__)
62
63NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
64 const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
65 : NativeRegisterContextRegisterInfo(native_thread,
66 new RegisterInfoPOSIX_arm(target_arch)),
67 NativeRegisterContextLinux(native_thread) {
68 assert(target_arch.GetMachine() == llvm::Triple::arm);
69
70 ::memset(&m_fpr, 0, sizeof(m_fpr));
71 ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
72 ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
73 ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
74
75 // 16 is just a maximum value, query hardware for actual watchpoint count
76 m_max_hwp_supported = 16;
77 m_max_hbp_supported = 16;
78 m_refresh_hwdebug_info = true;
79}
80
81RegisterInfoPOSIX_arm &NativeRegisterContextLinux_arm::GetRegisterInfo() const {
82 return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up);
83}
84
85uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
86 return GetRegisterInfo().GetRegisterSetCount();
87}
88
89uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const {
90 uint32_t count = 0;
91 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
92 count += GetRegisterSet(set_index)->num_registers;
93 return count;
94}
95
96const RegisterSet *
97NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const {
98 return GetRegisterInfo().GetRegisterSet(set_index);
99}
100
101Status
102NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo *reg_info,
103 RegisterValue &reg_value) {
104 Status error;
105
106 if (!reg_info) {
107 error.SetErrorString("reg_info NULL");
108 return error;
109 }
110
111 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
112
113 if (IsFPR(reg)) {
114 error = ReadFPR();
115 if (error.Fail())
116 return error;
117 } else {
118 uint32_t full_reg = reg;
119 bool is_subreg = reg_info->invalidate_regs &&
120 (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
121
122 if (is_subreg) {
123 // Read the full aligned 64-bit register.
124 full_reg = reg_info->invalidate_regs[0];
125 }
126
127 error = ReadRegisterRaw(full_reg, reg_value);
128
129 if (error.Success()) {
130 // If our read was not aligned (for ah,bh,ch,dh), shift our returned
131 // value one byte to the right.
132 if (is_subreg && (reg_info->byte_offset & 0x1))
133 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
134
135 // If our return byte size was greater than the return value reg size,
136 // then use the type specified by reg_info rather than the uint64_t
137 // default
138 if (reg_value.GetByteSize() > reg_info->byte_size)
139 reg_value.SetType(*reg_info);
140 }
141 return error;
142 }
143
144 // Get pointer to m_fpr variable and set the data from it.
145 uint32_t fpr_offset = CalculateFprOffset(reg_info);
146 assert(fpr_offset < sizeof m_fpr);
147 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset;
148 switch (reg_info->byte_size) {
149 case 2:
150 reg_value.SetUInt16(*(uint16_t *)src);
151 break;
152 case 4:
153 reg_value.SetUInt32(*(uint32_t *)src);
154 break;
155 case 8:
156 reg_value.SetUInt64(*(uint64_t *)src);
157 break;
158 case 16:
159 reg_value.SetBytes(src, 16, GetByteOrder());
160 break;
161 default:
162 assert(false && "Unhandled data size.");
163 error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
164 reg_info->byte_size);
165 break;
166 }
167
168 return error;
169}
170
171Status
172NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo *reg_info,
173 const RegisterValue &reg_value) {
174 if (!reg_info)
175 return Status("reg_info NULL");
176
177 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
178 if (reg_index == LLDB_INVALID_REGNUM)
179 return Status("no lldb regnum for %s", reg_info && reg_info->name
180 ? reg_info->name
181 : "<unknown register>");
182
183 if (IsGPR(reg_index))
184 return WriteRegisterRaw(reg_index, reg_value);
185
186 if (IsFPR(reg_index)) {
187 // Get pointer to m_fpr variable and set the data to it.
188 uint32_t fpr_offset = CalculateFprOffset(reg_info);
189 assert(fpr_offset < sizeof m_fpr);
190 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset;
191 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
192
193 return WriteFPR();
194 }
195
196 return Status("failed - register wasn't recognized to be a GPR or an FPR, "
197 "write strategy unknown");
198}
199
200Status NativeRegisterContextLinux_arm::ReadAllRegisterValues(
201 lldb::WritableDataBufferSP &data_sp) {
202 Status error;
203
204 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
205 error = ReadGPR();
206 if (error.Fail())
207 return error;
208
209 error = ReadFPR();
210 if (error.Fail())
211 return error;
212
213 uint8_t *dst = data_sp->GetBytes();
214 ::memcpy(dst, &m_gpr_arm, GetGPRSize());
215 dst += GetGPRSize();
216 ::memcpy(dst, &m_fpr, sizeof(m_fpr));
217
218 return error;
219}
220
221Status NativeRegisterContextLinux_arm::WriteAllRegisterValues(
222 const lldb::DataBufferSP &data_sp) {
223 Status error;
224
225 if (!data_sp) {
226 error.SetErrorStringWithFormat(
227 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
228 __FUNCTION__);
229 return error;
230 }
231
232 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
233 error.SetErrorStringWithFormat(
234 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
235 "data size, expected %" PRIu64 ", actual %" PRIu64,
236 __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize());
237 return error;
238 }
239
240 const uint8_t *src = data_sp->GetBytes();
241 if (src == nullptr) {
242 error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm::%s "
243 "DataBuffer::GetBytes() returned a null "
244 "pointer",
245 __FUNCTION__);
246 return error;
247 }
248 ::memcpy(&m_gpr_arm, src, GetRegisterInfoInterface().GetGPRSize());
249
250 error = WriteGPR();
251 if (error.Fail())
252 return error;
253
254 src += GetRegisterInfoInterface().GetGPRSize();
255 ::memcpy(&m_fpr, src, sizeof(m_fpr));
256
257 error = WriteFPR();
258 if (error.Fail())
259 return error;
260
261 return error;
262}
263
264bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const {
265 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
266 RegisterInfoPOSIX_arm::GPRegSet)
267 return true;
268 return false;
269}
270
271bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
272 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
273 RegisterInfoPOSIX_arm::FPRegSet)
274 return true;
275 return false;
276}
277
278uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
279 Log *log = GetLog(POSIXLog::Breakpoints);
280
281 LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
282
283 Status error;
284
285 // Read hardware breakpoint and watchpoint information.
286 error = ReadHardwareDebugInfo();
287
288 if (error.Fail())
289 return 0;
290
291 LLDB_LOG(log, "{0}", m_max_hbp_supported);
292 return m_max_hbp_supported;
293}
294
295uint32_t
296NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
297 size_t size) {
298 Log *log = GetLog(POSIXLog::Breakpoints);
299 LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
300
301 // Read hardware breakpoint and watchpoint information.
302 Status error = ReadHardwareDebugInfo();
303
304 if (error.Fail())
305 return LLDB_INVALID_INDEX32;
306
307 uint32_t control_value = 0, bp_index = 0;
308
309 // Setup address and control values.
310 // Use size to get a hint of arm vs thumb modes.
311 switch (size) {
312 case 2:
313 control_value = (0x3 << 5) | 7;
314 addr &= ~1;
315 break;
316 case 4:
317 control_value = (0xfu << 5) | 7;
318 addr &= ~3;
319 break;
320 default:
321 return LLDB_INVALID_INDEX32;
322 }
323
324 // Iterate over stored breakpoints and find a free bp_index
325 bp_index = LLDB_INVALID_INDEX32;
326 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
327 if ((m_hbr_regs[i].control & 1) == 0) {
328 bp_index = i; // Mark last free slot
329 } else if (m_hbr_regs[i].address == addr) {
330 return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
331 }
332 }
333
334 if (bp_index == LLDB_INVALID_INDEX32)
335 return LLDB_INVALID_INDEX32;
336
337 // Update breakpoint in local cache
338 m_hbr_regs[bp_index].real_addr = addr;
339 m_hbr_regs[bp_index].address = addr;
340 m_hbr_regs[bp_index].control = control_value;
341
342 // PTRACE call to set corresponding hardware breakpoint register.
343 error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index);
344
345 if (error.Fail()) {
346 m_hbr_regs[bp_index].address = 0;
347 m_hbr_regs[bp_index].control &= ~1;
348
349 return LLDB_INVALID_INDEX32;
350 }
351
352 return bp_index;
353}
354
355bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
356 Log *log = GetLog(POSIXLog::Breakpoints);
357 LLDB_LOG(log, "hw_idx: {0}", hw_idx);
358
359 // Read hardware breakpoint and watchpoint information.
360 Status error = ReadHardwareDebugInfo();
361
362 if (error.Fail())
363 return false;
364
365 if (hw_idx >= m_max_hbp_supported)
366 return false;
367
368 // Create a backup we can revert to in case of failure.
369 lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
370 uint32_t tempControl = m_hbr_regs[hw_idx].control;
371
372 m_hbr_regs[hw_idx].control &= ~1;
373 m_hbr_regs[hw_idx].address = 0;
374
375 // PTRACE call to clear corresponding hardware breakpoint register.
376 error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx);
377
378 if (error.Fail()) {
379 m_hbr_regs[hw_idx].control = tempControl;
380 m_hbr_regs[hw_idx].address = tempAddr;
381
382 return false;
383 }
384
385 return true;
386}
387
388Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
389 uint32_t &bp_index, lldb::addr_t trap_addr) {
390 Log *log = GetLog(POSIXLog::Breakpoints);
391
392 LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
393
394 lldb::addr_t break_addr;
395
396 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
397 break_addr = m_hbr_regs[bp_index].address;
398
399 if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
400 m_hbr_regs[bp_index].hit_addr = trap_addr;
401 return Status();
402 }
403 }
404
405 bp_index = LLDB_INVALID_INDEX32;
406 return Status();
407}
408
409Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
410 Log *log = GetLog(POSIXLog::Breakpoints);
411
412 LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
413
414 Status error;
415
416 // Read hardware breakpoint and watchpoint information.
417 error = ReadHardwareDebugInfo();
418
419 if (error.Fail())
420 return error;
421
422 lldb::addr_t tempAddr = 0;
423 uint32_t tempControl = 0;
424
425 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
426 if (m_hbr_regs[i].control & 0x01) {
427 // Create a backup we can revert to in case of failure.
428 tempAddr = m_hbr_regs[i].address;
429 tempControl = m_hbr_regs[i].control;
430
431 // Clear breakpoints in local cache
432 m_hbr_regs[i].control &= ~1;
433 m_hbr_regs[i].address = 0;
434
435 // Ptrace call to update hardware debug registers
436 error = WriteHardwareDebugRegs(eDREGTypeBREAK, i);
437
438 if (error.Fail()) {
439 m_hbr_regs[i].control = tempControl;
440 m_hbr_regs[i].address = tempAddr;
441
442 return error;
443 }
444 }
445 }
446
447 return Status();
448}
449
450uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
451 Log *log = GetLog(POSIXLog::Watchpoints);
452
453 // Read hardware breakpoint and watchpoint information.
454 Status error = ReadHardwareDebugInfo();
455
456 if (error.Fail())
457 return 0;
458
459 LLDB_LOG(log, "{0}", m_max_hwp_supported);
460 return m_max_hwp_supported;
461}
462
463uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
464 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
465 Log *log = GetLog(POSIXLog::Watchpoints);
466 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
467 watch_flags);
468
469 // Read hardware breakpoint and watchpoint information.
470 Status error = ReadHardwareDebugInfo();
471
472 if (error.Fail())
473 return LLDB_INVALID_INDEX32;
474
475 uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
476 lldb::addr_t real_addr = addr;
477
478 // Check if we are setting watchpoint other than read/write/access Also
479 // update watchpoint flag to match Arm write-read bit configuration.
480 switch (watch_flags) {
481 case 1:
482 watch_flags = 2;
483 break;
484 case 2:
485 watch_flags = 1;
486 break;
487 case 3:
488 break;
489 default:
490 return LLDB_INVALID_INDEX32;
491 }
492
493 // Can't watch zero bytes
494 // Can't watch more than 4 bytes per WVR/WCR pair
495
496 if (size == 0 || size > 4)
497 return LLDB_INVALID_INDEX32;
498
499 // Check 4-byte alignment for hardware watchpoint target address. Below is a
500 // hack to recalculate address and size in order to make sure we can watch
501 // non 4-byte aligned addresses as well.
502 if (addr & 0x03) {
503 uint8_t watch_mask = (addr & 0x03) + size;
504
505 if (watch_mask > 0x04)
506 return LLDB_INVALID_INDEX32;
507 else if (watch_mask <= 0x02)
508 size = 2;
509 else if (watch_mask <= 0x04)
510 size = 4;
511
512 addr = addr & (~0x03);
513 }
514
515 // We can only watch up to four bytes that follow a 4 byte aligned address
516 // per watchpoint register pair, so make sure we can properly encode this.
517 addr_word_offset = addr % 4;
518 byte_mask = ((1u << size) - 1u) << addr_word_offset;
519
520 // Check if we need multiple watchpoint register
521 if (byte_mask > 0xfu)
522 return LLDB_INVALID_INDEX32;
523
524 // Setup control value
525 // Make the byte_mask into a valid Byte Address Select mask
526 control_value = byte_mask << 5;
527
528 // Turn on appropriate watchpoint flags read or write
529 control_value |= (watch_flags << 3);
530
531 // Enable this watchpoint and make it stop in privileged or user mode;
532 control_value |= 7;
533
534 // Make sure bits 1:0 are clear in our address
535 addr &= ~((lldb::addr_t)3);
536
537 // Iterate over stored watchpoints and find a free wp_index
538 wp_index = LLDB_INVALID_INDEX32;
539 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
540 if ((m_hwp_regs[i].control & 1) == 0) {
541 wp_index = i; // Mark last free slot
542 } else if (m_hwp_regs[i].address == addr) {
543 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
544 }
545 }
546
547 if (wp_index == LLDB_INVALID_INDEX32)
548 return LLDB_INVALID_INDEX32;
549
550 // Update watchpoint in local cache
551 m_hwp_regs[wp_index].real_addr = real_addr;
552 m_hwp_regs[wp_index].address = addr;
553 m_hwp_regs[wp_index].control = control_value;
554
555 // PTRACE call to set corresponding watchpoint register.
556 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
557
558 if (error.Fail()) {
559 m_hwp_regs[wp_index].address = 0;
560 m_hwp_regs[wp_index].control &= ~1;
561
562 return LLDB_INVALID_INDEX32;
563 }
564
565 return wp_index;
566}
567
568bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
569 uint32_t wp_index) {
570 Log *log = GetLog(POSIXLog::Watchpoints);
571 LLDB_LOG(log, "wp_index: {0}", wp_index);
572
573 // Read hardware breakpoint and watchpoint information.
574 Status error = ReadHardwareDebugInfo();
575
576 if (error.Fail())
577 return false;
578
579 if (wp_index >= m_max_hwp_supported)
580 return false;
581
582 // Create a backup we can revert to in case of failure.
583 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
584 uint32_t tempControl = m_hwp_regs[wp_index].control;
585
586 // Update watchpoint in local cache
587 m_hwp_regs[wp_index].control &= ~1;
588 m_hwp_regs[wp_index].address = 0;
589
590 // Ptrace call to update hardware debug registers
591 error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index);
592
593 if (error.Fail()) {
594 m_hwp_regs[wp_index].control = tempControl;
595 m_hwp_regs[wp_index].address = tempAddr;
596
597 return false;
598 }
599
600 return true;
601}
602
603Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
604 // Read hardware breakpoint and watchpoint information.
605 Status error = ReadHardwareDebugInfo();
606
607 if (error.Fail())
608 return error;
609
610 lldb::addr_t tempAddr = 0;
611 uint32_t tempControl = 0;
612
613 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
614 if (m_hwp_regs[i].control & 0x01) {
615 // Create a backup we can revert to in case of failure.
616 tempAddr = m_hwp_regs[i].address;
617 tempControl = m_hwp_regs[i].control;
618
619 // Clear watchpoints in local cache
620 m_hwp_regs[i].control &= ~1;
621 m_hwp_regs[i].address = 0;
622
623 // Ptrace call to update hardware debug registers
624 error = WriteHardwareDebugRegs(eDREGTypeWATCH, i);
625
626 if (error.Fail()) {
627 m_hwp_regs[i].control = tempControl;
628 m_hwp_regs[i].address = tempAddr;
629
630 return error;
631 }
632 }
633 }
634
635 return Status();
636}
637
638uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
639 Log *log = GetLog(POSIXLog::Watchpoints);
640 LLDB_LOG(log, "wp_index: {0}", wp_index);
641
642 switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
643 case 0x01:
644 return 1;
645 case 0x03:
646 return 2;
647 case 0x07:
648 return 3;
649 case 0x0f:
650 return 4;
651 default:
652 return 0;
653 }
654}
655bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
656 Log *log = GetLog(POSIXLog::Watchpoints);
657 LLDB_LOG(log, "wp_index: {0}", wp_index);
658
659 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
660 return true;
661 else
662 return false;
663}
664
665Status
666NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
667 lldb::addr_t trap_addr) {
668 Log *log = GetLog(POSIXLog::Watchpoints);
669 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
670
671 uint32_t watch_size;
672 lldb::addr_t watch_addr;
673
674 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
675 watch_size = GetWatchpointSize(wp_index);
676 watch_addr = m_hwp_regs[wp_index].address;
677
678 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
679 trap_addr < watch_addr + watch_size) {
680 m_hwp_regs[wp_index].hit_addr = trap_addr;
681 return Status();
682 }
683 }
684
685 wp_index = LLDB_INVALID_INDEX32;
686 return Status();
687}
688
689lldb::addr_t
690NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
691 Log *log = GetLog(POSIXLog::Watchpoints);
692 LLDB_LOG(log, "wp_index: {0}", wp_index);
693
694 if (wp_index >= m_max_hwp_supported)
695 return LLDB_INVALID_ADDRESS;
696
697 if (WatchpointIsEnabled(wp_index))
698 return m_hwp_regs[wp_index].real_addr;
699 else
700 return LLDB_INVALID_ADDRESS;
701}
702
703lldb::addr_t
704NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
705 Log *log = GetLog(POSIXLog::Watchpoints);
706 LLDB_LOG(log, "wp_index: {0}", wp_index);
707
708 if (wp_index >= m_max_hwp_supported)
709 return LLDB_INVALID_ADDRESS;
710
711 if (WatchpointIsEnabled(wp_index))
712 return m_hwp_regs[wp_index].hit_addr;
713 else
714 return LLDB_INVALID_ADDRESS;
715}
716
717Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
718 Status error;
719
720 if (!m_refresh_hwdebug_info) {
721 return Status();
722 }
723
724 unsigned int cap_val;
725
726 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
727 nullptr, &cap_val,
728 sizeof(unsigned int));
729
730 if (error.Fail())
731 return error;
732
733 m_max_hwp_supported = (cap_val >> 8) & 0xff;
734 m_max_hbp_supported = cap_val & 0xff;
735 m_refresh_hwdebug_info = false;
736
737 return error;
738}
739
740Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType,
741 int hwb_index) {
742 Status error;
743
744 lldb::addr_t *addr_buf;
745 uint32_t *ctrl_buf;
746
747 if (hwbType == eDREGTypeWATCH) {
748 addr_buf = &m_hwp_regs[hwb_index].address;
749 ctrl_buf = &m_hwp_regs[hwb_index].control;
750
751 error = NativeProcessLinux::PtraceWrapper(
752 PTRACE_SETHBPREGS, m_thread.GetID(),
753 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
754 sizeof(unsigned int));
755
756 if (error.Fail())
757 return error;
758
759 error = NativeProcessLinux::PtraceWrapper(
760 PTRACE_SETHBPREGS, m_thread.GetID(),
761 (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
762 sizeof(unsigned int));
763 } else {
764 addr_buf = &m_hbr_regs[hwb_index].address;
765 ctrl_buf = &m_hbr_regs[hwb_index].control;
766
767 error = NativeProcessLinux::PtraceWrapper(
768 PTRACE_SETHBPREGS, m_thread.GetID(),
769 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
770 sizeof(unsigned int));
771
772 if (error.Fail())
773 return error;
774
775 error = NativeProcessLinux::PtraceWrapper(
776 PTRACE_SETHBPREGS, m_thread.GetID(),
777 (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
778 sizeof(unsigned int));
779 }
780
781 return error;
782}
783
784uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
785 const RegisterInfo *reg_info) const {
786 return reg_info->byte_offset - GetGPRSize();
787}
788
789Status NativeRegisterContextLinux_arm::DoReadRegisterValue(
790 uint32_t offset, const char *reg_name, uint32_t size,
791 RegisterValue &value) {
792 // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
793 // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we
794 // read out the full GPR register set instead. This approach is about 4 times
795 // slower but the performance overhead is negligible in comparison to
796 // processing time in lldb-server.
797 assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
798 if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
799 return Status("Register isn't fit into the size of the GPR area");
800
801 Status error = ReadGPR();
802 if (error.Fail())
803 return error;
804
805 value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
806 return Status();
807}
808
809Status NativeRegisterContextLinux_arm::DoWriteRegisterValue(
810 uint32_t offset, const char *reg_name, const RegisterValue &value) {
811 // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
812 // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we
813 // read out the full GPR register set, modify the requested register and
814 // write it back. This approach is about 4 times slower but the performance
815 // overhead is negligible in comparison to processing time in lldb-server.
816 assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
817 if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
818 return Status("Register isn't fit into the size of the GPR area");
819
820 Status error = ReadGPR();
821 if (error.Fail())
822 return error;
823
824 uint32_t reg_value = value.GetAsUInt32();
825 // As precaution for an undefined behavior encountered while setting PC we
826 // will clear thumb bit of new PC if we are already in thumb mode; that is
827 // CPSR thumb mode bit is set.
828 if (offset / sizeof(uint32_t) == gpr_pc_arm) {
829 // Check if we are already in thumb mode and thumb bit of current PC is
830 // read out to be zero and thumb bit of next PC is read out to be one.
831 if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && !(m_gpr_arm[gpr_pc_arm] & 0x01) &&
832 (value.GetAsUInt32() & 0x01)) {
833 reg_value &= (~1ull);
834 }
835 }
836
837 m_gpr_arm[offset / sizeof(uint32_t)] = reg_value;
838 return WriteGPR();
839}
840
841Status NativeRegisterContextLinux_arm::ReadGPR() {
842#ifdef __arm__
843 return NativeRegisterContextLinux::ReadGPR();
844#else // __aarch64__
845 struct iovec ioVec;
846 ioVec.iov_base = GetGPRBuffer();
847 ioVec.iov_len = GetGPRSize();
848
849 return ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
850#endif // __arm__
851}
852
853Status NativeRegisterContextLinux_arm::WriteGPR() {
854#ifdef __arm__
855 return NativeRegisterContextLinux::WriteGPR();
856#else // __aarch64__
857 struct iovec ioVec;
858 ioVec.iov_base = GetGPRBuffer();
859 ioVec.iov_len = GetGPRSize();
860
861 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
862#endif // __arm__
863}
864
865Status NativeRegisterContextLinux_arm::ReadFPR() {
866#ifdef __arm__
867 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS, m_thread.GetID(),
868 nullptr, GetFPRBuffer(),
869 GetFPRSize());
870#else // __aarch64__
871 struct iovec ioVec;
872 ioVec.iov_base = GetFPRBuffer();
873 ioVec.iov_len = GetFPRSize();
874
875 return ReadRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
876#endif // __arm__
877}
878
879Status NativeRegisterContextLinux_arm::WriteFPR() {
880#ifdef __arm__
881 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS, m_thread.GetID(),
882 nullptr, GetFPRBuffer(),
883 GetFPRSize());
884#else // __aarch64__
885 struct iovec ioVec;
886 ioVec.iov_base = GetFPRBuffer();
887 ioVec.iov_len = GetFPRSize();
888
889 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_ARM_VFP);
890#endif // __arm__
891}
892
893#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
894

source code of lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp