Page MenuHomePhabricator

Fix ARM/AArch64 Step-Over watchpoint issue remove provision for duplicate watchpoints
ClosedPublic

Authored by omjavaid on Sep 28 2016, 5:26 PM.

Details

Summary

On ARM Linux targets watchpoints are reported by PTrace before the instruction causing watchpoint to trigger is executed.
This means we cannot step-over watchpoint causing instruction as long as there is watchpoint installed on that location.
For this reason we cannot have multiple watchpoint slots watching same region word/byte/halfword etc as we have to disable watchpoint for stepping over and only watchpoint index reported by lldb-server is disabled.
Similarly we cannot keep a single hardware watchpoint slot referring to multiple watchpoints in LLDB. This actually means that hware watchpoint indexes are exclusively assigned to a watchpoint and cannot be shared by other watchpoint. Also no other watchpoint should watch same address already watched by any other index.

More discussion on this can be found here:
https://reviews.llvm.org/D24610

This patch fixes issue with stepping over watchpoint by removing the provision to enable multiple watchpoints referring to same hardware watchpoint slot (same HW index). Also we restrict one watchpoint per word aligned address so duplication of address will not be allowed to avoid any step-over failures.

I have also attached a test-case that tests this scenario.

Diff Detail

Repository
rL LLVM

Event Timeline

omjavaid updated this revision to Diff 72932.Sep 28 2016, 5:26 PM
omjavaid retitled this revision from to Fix ARM/AArch64 Step-Over watchpoint issue remove provision for duplicate watchpoints.
omjavaid updated this object.
omjavaid added a reviewer: labath.
omjavaid added a subscriber: lldb-commits.

@labath Referring to your email on the mailing list.

Thanks for helping out with this work.

I think we should push this fix, as you suggested this does not fix everything in a holistic way but it corrects the functionality that is currently available right now with limitations ofcourse.

So here is functionality we are currently lacking:

  • Ability to put multiple watchpoints with same address range.

This is more concerning because we cannot put a watch on say byte 0 and byte 7 in case of aarch64.

  • Ability to use single slot for multiple watchpoints.

This is more like a nice to have and I think if we fix the above functionality this may well be fixed automatically.

This is what I think LLDB client or server has to do:

  • Keep a cache of watchpoint registers available and modify registers in cache when a set/remove request is made.
  • As pre-req for set/remove is to have the target in stopped state this will mean that when we set/remove we make changes to actual registers before we resume for continue or stepping.
  • I dont think keeping the cache and then updating on resume actually means we are lying to client. Cache will also remain limited and will behave like an actual write to the registers. It will serve us well to support the functionality we intend to support.

In case of GDB this functionality is handled by gdbserver and gdb client is not aware of the fact that watchpoint registers are not actually written until we resume.

To implement this in LLDB client or server is a design decision and I just see that it should be easier to achieve on LLDB server side though it may require changes to the way we approach watchpoint for all targets but it will then remain restricted to the concerning target specific area.

I am OOO till 16th If you are OK with this change I will push it whenever it gets a LGTM.

labath edited edge metadata.Oct 4 2016, 9:28 AM

@labath Referring to your email on the mailing list.

Thanks for helping out with this work.

I think we should push this fix, as you suggested this does not fix everything in a holistic way but it corrects the functionality that is currently available right now with limitations ofcourse.

So here is functionality we are currently lacking:

  • Ability to put multiple watchpoints with same address range. This is more concerning because we cannot put a watch on say byte 0 and byte 7 in case of aarch64.

Agreed. However, I'd rephrase this as "ability to correctly handle a single instruction triggering multiple watchpoints. If done properly, you will get the previous item for free.

Also, apparently lldb has a bug, where it mishandles the case where you do a (user-level) single step over an instruction triggering a watchpoint. That would be pretty important to fix as well.

  • Ability to use single slot for multiple watchpoints. This is more like a nice to have and I think if we fix the above functionality this may well be fixed automatically.

I am not sure I agree with this, but I'd have to see the implementation to tell. One of the issues I have with reusing same slot for multiple watchpoints is that it does not work at all for the "read" case, and even the "write" case is extremely dodgy. Normally a "write" watchpoint should trigger whenever the memory is written to, but here we are treating it more like a "modify" watchpoint, where we stop only if the write actually modifies the memory value. Reusing a slot for "modify" watchpoints is easy, doing it correctly for the "write" case is quite hard.

This is what I think LLDB client or server has to do:

  • Keep a cache of watchpoint registers available and modify registers in cache when a set/remove request is made.

Sure, why not.

  • As pre-req for set/remove is to have the target in stopped state this will mean that when we set/remove we make changes to actual registers before we resume for continue or stepping.

OK, you cannot set watchpoint set/clear packets while the target is running anyway.

  • I dont think keeping the cache and then updating on resume actually means we are lying to client. Cache will also remain limited and will behave like an actual write to the registers. It will serve us well to support the functionality we intend to support.

It depends, on whether the fact that we don't write to the registers immediately has any observable effects for the client. In your previous patch, it did. This happened because you were only syncing the registers on a resume, so if the client did a single-step instead, the watch would not trigger. This is what I consider "lying", and violating the gdb-remote protocol. If the client cannot tell the difference, you are free to do whatever you want.

In case of GDB this functionality is handled by gdbserver and gdb client is not aware of the fact that watchpoint registers are not actually written until we resume.

This is interesting. Can you tell me what is the packet sequence in the case where the client has watchpoints set at 0x1000 and 0x1001 and an instruction trips both of them?

To implement this in LLDB client or server is a design decision and I just see that it should be easier to achieve on LLDB server side though it may require changes to the way we approach watchpoint for all targets but it will then remain restricted to the concerning target specific area.

I don't see how you can handle the case when an instruction trips two watchpoints in different slots with server-side changes only. If it can be done, then it is a design decision, but until then, I believe it is a decision between a correct and a partial solution, and I'd go with the fully correct one.

I am OOO till 16th If you are OK with this change I will push it whenever it gets a LGTM.

Some small nits on the patch you should fix before committing. Otherwise, looks good.

packages/Python/lldbsuite/test/functionalities/watchpoint/multi_watchpoint_slots/TestWatchpointMultipleSlots.py
35 ↗(On Diff #72932)

this is unnecesary, as the test is already skipped.

39 ↗(On Diff #72932)

this is unnecesary, as the test is already skipped.

source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
579 ↗(On Diff #72932)

The formatting here is incorrect. Please run clang-format on the patch.

source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
547 ↗(On Diff #72932)

ditto

omjavaid updated this revision to Diff 75103.Oct 18 2016, 8:51 PM
omjavaid edited edge metadata.

Sorry I was on Holiday so couldnt get back to this earlier.

I ll get back to your comments about GDB packet sequence in a separate thread after collecting further information.

I have made the suggested corrections in above patch.

labath accepted this revision.Oct 19 2016, 3:53 AM
labath edited edge metadata.

LGTM, thanks.

BTW, it looks like the linux kernel is about to grow support for proper byte-range watchpoints http://lists.infradead.org/pipermail/linux-arm-kernel/2016-October/461036.html.

This revision is now accepted and ready to land.Oct 19 2016, 3:53 AM
This revision was automatically updated to reflect the committed changes.