https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/209483
>From 765ae437a29c80143744a53632e8bf339710f586 Mon Sep 17 00:00:00 2001 From: David Spickett <[email protected]> Date: Mon, 13 Jul 2026 15:46:52 +0000 Subject: [PATCH 1/2] [lldb][AArch64][NFC] Make watchpoint adjustment more clear NativeRegisterContextDBReg_arm64::AdjustWatchpoint has a way of adjusting the range of a watchpoint to fit hardware expectations but it took me a while to figure out how it worked. I've rewritten it in a way I think is easier to follow, with more explanatory comments. --- .../NativeRegisterContextDBReg_arm64.cpp | 65 +++++++++++++------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp index f2f772ad615c9..fff11c47c1395 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp @@ -12,6 +12,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" +#include "llvm/Support/MathExtras.h" + using namespace lldb_private; uint32_t @@ -36,30 +38,55 @@ NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) { std::optional<NativeRegisterContextDBReg::WatchpointDetails> NativeRegisterContextDBReg_arm64::AdjustWatchpoint( const WatchpointDetails &details) { + // A BAS watchpoint's size must be a power of 2 that is no greater than 8. + const size_t max_size = 8; size_t size = details.size; - lldb::addr_t addr = details.addr; - // Check if size has a valid hardware watchpoint length. - if (size != 1 && size != 2 && size != 4 && size != 8) + if (!llvm::isPowerOf2_64(size) || size > max_size) return std::nullopt; - // Check 8-byte alignment for hardware watchpoint target address. Below is a - // hack to recalculate address and size in order to make sure we can watch - // non 8-byte aligned addresses as well. - if (addr & 0x07) { - uint8_t watch_mask = (addr & 0x07) + size; - - if (watch_mask > 0x08) - return std::nullopt; + // The start address must be aligned to 8 bytes. + lldb::addr_t addr = details.addr; + const size_t misalignment = addr & (max_size - 1); + if (misalignment == 0) + return details; + + // The start address is not aligned, but we might be able to expand the + // watched range backwards to the previous 8 byte aligned address while + // keeping the size <= 8 bytes. + // + // Aligned Address + // | /--------- Start Address + // [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ] + // | |<-------- Size ------->| + // |<----- Aligned Size -------->| + // + size_t aligned_size = misalignment + size; + if (aligned_size > max_size) { + // The range does not fit within a single BAS watchpoint, reject it. + return std::nullopt; + } - if (watch_mask <= 0x02) - size = 2; - else if (watch_mask <= 0x04) - size = 4; - else - size = 8; + // Size must still be a power of 2. After correcting this, sometimes we will + // watch bytes before and after the intended range. Stops in these extra bytes + // will be filtered out. + // + // For example, A is an aligned address and S is the start address. You want + // to watch the 1 byte at address S. + // [A][ ][S][ ] + // { } + // This is misaligned by 2, so our aligned size is 3. + // [A][ ][S][ ] + // { } + // We cannot watch 3 bytes but we can watch 4. + // [A][ ][S][ ] + // { } + // The watched range is expanded before and after S. + + // Round up to a power of 2 size. + size = llvm::PowerOf2Ceil(aligned_size); + // Align the address down. + addr -= misalignment; - addr = addr & (~0x07); - } return WatchpointDetails{size, addr}; } >From 103ae09e5ce360e846bae0e360c8028535758d7d Mon Sep 17 00:00:00 2001 From: David Spickett <[email protected]> Date: Wed, 15 Jul 2026 12:47:33 +0000 Subject: [PATCH 2/2] update comments --- .../Utility/NativeRegisterContextDBReg_arm64.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp index fff11c47c1395..91c440f4c0453 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp @@ -38,7 +38,8 @@ NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) { std::optional<NativeRegisterContextDBReg::WatchpointDetails> NativeRegisterContextDBReg_arm64::AdjustWatchpoint( const WatchpointDetails &details) { - // A BAS watchpoint's size must be a power of 2 that is no greater than 8. + // For the way we are using BAS watchpoints, their size must be a power of 2 + // that is less than 8. Note that this is a subset of what hardware allows. const size_t max_size = 8; size_t size = details.size; if (!llvm::isPowerOf2_64(size) || size > max_size) @@ -94,14 +95,15 @@ uint32_t NativeRegisterContextDBReg_arm64::MakeBreakControlValue(size_t size) { // PAC (bits 2:1): 0b10 const uint32_t pac_bits = 2 << 1; - // BAS (bits 12:5) hold a bit-mask of addresses to watch + // BAS (bits 12:5) hold a bit-mask of addresses to watch. + // Hardware does allow gaps but we only support unbroken ranges at this time + // // e.g. 0b00000001 means 1 byte at address // 0b00000011 means 2 bytes (addr..addr+1) // ... // 0b11111111 means 8 bytes (addr..addr+7) size_t encoded_size = ((1 << size) - 1) << 5; - // Return encoded hardware breakpoint control value. return m_hw_dbg_enable_bit | pac_bits | encoded_size; } @@ -111,13 +113,14 @@ NativeRegisterContextDBReg_arm64::MakeWatchControlValue(size_t size, // PAC (bits 2:1): 0b10 const uint32_t pac_bits = 2 << 1; - // BAS (bits 12:5) hold a bit-mask of addresses to watch + // BAS (bits 12:5) hold a bit-mask of addresses to watch. + // Hardware does allow gaps but we only support unbroken ranges at this time. + // // e.g. 0b00000001 means 1 byte at address // 0b00000011 means 2 bytes (addr..addr+1) // ... // 0b11111111 means 8 bytes (addr..addr+7) size_t encoded_size = ((1 << size) - 1) << 5; - // Return encoded hardware watchpoint control value. return m_hw_dbg_enable_bit | pac_bits | encoded_size | (watch_flags << 3); } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
