Bug 200965 - Setting a disabled HW breakpoint's address to an unaligned value fails
Summary: Setting a disabled HW breakpoint's address to an unaligned value fails
Status: RESOLVED CODE_FIX
Alias: None
Product: Process Management
Classification: Unclassified
Component: Other (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: process_other
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-08-29 02:10 UTC by Robert O'Callahan
Modified: 2023-03-27 02:10 UTC (History)
4 users (show)

See Also:
Kernel Version: 4.17.14-202.fc28.x86_64
Subsystem:
Regression: No
Bisected commit-id:


Attachments
Test program (1.06 KB, text/x-csrc)
2018-08-29 02:10 UTC, Robert O'Callahan
Details

Description Robert O'Callahan 2018-08-29 02:10:01 UTC
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.
Comment 1 Alexandre Julliard 2018-12-18 15:14:49 UTC
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.
Comment 2 Rémi Bernon 2021-10-29 15:06:32 UTC
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.

Note You need to log in before you can comment on or make changes to this bug.