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