================
@@ -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.
----------------
DavidSpickett wrote:
```
D2.9.5.2 Programming a watchpoint range with eight bytes or fewer
The Byte Address Select field, DBGWCR<n>_EL1.BAS, selects bytes in the
doubleword starting at the address
contained in DBGWVR<n>_EL1.
```
It says "starting" but it doesn't mean you have to select byte 1 and 2 if you
only wanted byte 2.
Another thing I did not realise:
```
* Doubleword-aligned:
All eight bits of DBGWCR<n>_EL1.BAS are used.
* Word-aligned but not doubleword-aligned:
Only DBGWCR<n>_EL1.BAS[3:0] are used. In this case, DBGWCR<n>_EL1.BAS[7:4] are
RES0.
```
So there's two self imposed limitations:
* That we select a continuous range of bytes starting from the aligned address
* That we align the address only to 8 bytes when 4 is also allowed
I'll update the comments to make that clear and go ahead with this PR. I'll
tackle these limitations next.
Thanks for pointing that out, I had only got so far as reading our own code.
https://github.com/llvm/llvm-project/pull/209483
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits