xref: /llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp (revision ae5836f6b6a8544e6226f5c1ba6b1beacfe01aef)
1 //===-- NativeRegisterContextDBReg_arm64.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 #include "NativeRegisterContextDBReg_arm64.h"
10 
11 #include "lldb/Utility/LLDBLog.h"
12 #include "lldb/Utility/Log.h"
13 #include "lldb/Utility/RegisterValue.h"
14 
15 using namespace lldb_private;
16 
17 uint32_t
18 NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) {
19   Log *log = GetLog(LLDBLog::Watchpoints);
20   LLDB_LOG(log, "wp_index: {0}", wp_index);
21 
22   switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
23   case 0x01:
24     return 1;
25   case 0x03:
26     return 2;
27   case 0x0f:
28     return 4;
29   case 0xff:
30     return 8;
31   default:
32     return 0;
33   }
34 }
35 
36 std::optional<NativeRegisterContextDBReg::WatchpointDetails>
37 NativeRegisterContextDBReg_arm64::AdjustWatchpoint(
38     const WatchpointDetails &details) {
39   size_t size = details.size;
40   lldb::addr_t addr = details.addr;
41   // Check if size has a valid hardware watchpoint length.
42   if (size != 1 && size != 2 && size != 4 && size != 8)
43     return std::nullopt;
44 
45   // Check 8-byte alignment for hardware watchpoint target address. Below is a
46   // hack to recalculate address and size in order to make sure we can watch
47   // non 8-byte aligned addresses as well.
48   if (addr & 0x07) {
49     uint8_t watch_mask = (addr & 0x07) + size;
50 
51     if (watch_mask > 0x08)
52       return std::nullopt;
53 
54     if (watch_mask <= 0x02)
55       size = 2;
56     else if (watch_mask <= 0x04)
57       size = 4;
58     else
59       size = 8;
60 
61     addr = addr & (~0x07);
62   }
63   return WatchpointDetails{size, addr};
64 }
65 
66 uint32_t NativeRegisterContextDBReg_arm64::MakeBreakControlValue(size_t size) {
67   // PAC (bits 2:1): 0b10
68   const uint32_t pac_bits = 2 << 1;
69 
70   // BAS (bits 12:5) hold a bit-mask of addresses to watch
71   // e.g. 0b00000001 means 1 byte at address
72   //      0b00000011 means 2 bytes (addr..addr+1)
73   //      ...
74   //      0b11111111 means 8 bytes (addr..addr+7)
75   size_t encoded_size = ((1 << size) - 1) << 5;
76 
77   // Return encoded hardware breakpoint control value.
78   return m_hw_dbg_enable_bit | pac_bits | encoded_size;
79 }
80 
81 uint32_t
82 NativeRegisterContextDBReg_arm64::MakeWatchControlValue(size_t size,
83                                                         uint32_t watch_flags) {
84   // PAC (bits 2:1): 0b10
85   const uint32_t pac_bits = 2 << 1;
86 
87   // BAS (bits 12:5) hold a bit-mask of addresses to watch
88   // e.g. 0b00000001 means 1 byte at address
89   //      0b00000011 means 2 bytes (addr..addr+1)
90   //      ...
91   //      0b11111111 means 8 bytes (addr..addr+7)
92   size_t encoded_size = ((1 << size) - 1) << 5;
93 
94   // Return encoded hardware watchpoint control value.
95   return m_hw_dbg_enable_bit | pac_bits | encoded_size | (watch_flags << 3);
96 }
97