Created attachment 278189 [details] Test program See attached test program. If you set an 8-byte HW breakpoint to an aligned address, then clear DR7, then set the HW breakpoint to an unaligned address, that last operation fails. This is unexpected; clearing DR7 should disable all HW breakpoints *and* set their length to 1 byte. This fails because while clearing DR7, the kernel's modify_user_hw_breakpoint() doesn't update any breakpoint state if the breakpoint is being disabled. So the kernel's internal breakpoint keeps its 8-byte size, and setting its address to unaligned fails.
This is breaking debug registers support in Wine. It's a regression, it used to work. We get regression test failures on the Wine testbot for boxes running kernel 4.18, for instance: https://test.winehq.org/data/ec2c2f9fa0c964a00c97302523321b1d03550a62/linux_fg-acer64-wow64/ntdll:exception.html The testbot boxes running kernel 4.9 don't show any failure.
I investigated this issue a bit to better understand Wine's workaround and I believe the bug has been resolved since 4.19. The problem was introduced by 2d074918fb1568f398777343ff9a28049fb86337 conflict resolution, as the modify_user_hw_breakpoint function was changed both in 18ff57b220610a699947f20b156a8245ca7eee98 and in f67b15037a7a50c57f72e69a6d59941ad90a0f0f. Both commits were doing a bit of refactoring, but the breakpoint attribute (and more specifically its length) was still updated even if the breakpoint was being disabled. The conflict resolution added a "if (!attr->disabled)" check before modifying the other attributes, and I believe it (although I didn't actually confirm it) it caused the length attribute to not be updated anymore when the breakpoint was disabled. Later, bd14406b78e6daa1ea3c1673bda1ffc9efdeead0, which is in 4.19, changed it again and removed the incorrect condition. I confirmed that the attached sample program above works as it should with recent kernel versions.