This is an archive of the discontinued LLVM Phabricator instance.

Handle hardcoded breakpoints on Windows (e.g., int3 or __debugbreak())
ClosedPublic

Authored by amccarth on Dec 30 2015, 5:06 PM.

Details

Reviewers
zturner
labath
Summary

No hurry on the review. This can go in next year. :-)

This required a little rejiggering of ProcessWindowsLive::RefreshStateAfterStop in order to treat an unexpected breakpoint opcode as an exception worth stopping on.

Added a Windows-only test to check it out. In the future, the test probably could be generalized to handle other platforms.

Diff Detail

Event Timeline

amccarth updated this revision to Diff 43816.Dec 30 2015, 5:06 PM
amccarth retitled this revision from to Handle hardcoded breakpoints on Windows (e.g., int3 or __debugbreak()).
amccarth updated this object.
amccarth added a reviewer: zturner.
amccarth added a subscriber: lldb-commits.
zturner added inline comments.Dec 30 2015, 6:35 PM
source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
601–605

When you do a disassembly, does the arrow point to the int 3 or to the instruction after the int 3?

Also what does the output look like when you do a backtrace?

labath added a subscriber: labath.Jan 4 2016, 12:57 AM

Linux tests the same functionality in TestBuiltinTrap.py. Would it make sense to merge these two tests, given that the only difference is which compiler intrinsic is used to generate the int3 trap?

Linux tests the same functionality in TestBuiltinTrap.py. Would it make sense to merge these two tests, given that the only difference is which compiler intrinsic is used to generate the int3 trap?

Yes, it makes sense to combine the tests. The existing test does use the SB API very well, and TestBuiltinTrap.py is in a Linux-specific part of the test tree, so this may be more of re-working the Linux test to work much like this new one.

source/Plugins/Process/Windows/Live/ProcessWindowsLive.cpp
601–605

It points to the instruction after the int 3.

(lldb) thread backtrace

  • thread #1: tid = 0x4d70, 0x00a8903b a.out`main(argc=1, argv=0x0019c800) + 59 at main.c:12, stop reason = Exception 0x80000003 encountered at address 0xa8903a
    • frame #0: 0x00a8903b a.out`main(argc=1, argv=0x0019c800) + 59 at main.c:12 frame #1: 0x00a89157 a.out`.text$mn + 254
jingham added a subscriber: jingham.Jan 4 2016, 6:34 PM

Shouldn't we just remove the Linux test case in favor of your test case? The notion of a builtin_trap of some sort or other seems general. And, it looks like both the Linux port and the Windows port needed to do something to handle this specially so having a generic test might point out that this needs work the next time there is a new OS port. So having another test on the Linux side just seems confusing.

labath added a comment.Jan 5 2016, 2:06 AM

I agree that the new test is better than the existing linux one, which can therefore be removed. If you wish, I can do it after you get this in.

amccarth updated this revision to Diff 44179.Jan 6 2016, 4:04 PM

I've rolled bits of TestBuiltinTrap.py into the new test and deleted the old one.

This still works on Windows. I'm not set up to test it on Linux.

PTAL: I've enhanced the test to do a couple extra checks that TestBuiltinTrap.py was doing, and I've eliminated that old test.

I believe it should work on Linux as well as Windows, but I'm not set up with a Linux machine right now. If someone could try this patch on Linux, I'd appreciate it.

If/when this lands, I'll update https://llvm.org/bugs/show_bug.cgi?id=15936 to refer to the new test.

labath added a comment.Jan 7 2016, 2:42 AM

Hm.. it seems I have misunderstood the purpose of __builtin_trap and the respective test. The function seems to generate in illegal opcode (ud2) instead of the expected int3 breakpoint. And according to the original commit message, it seems the test was added to verify that this illegal instruction does not confuse lldb/llvm. After ud2/SIGILL, it is not possible (without additional tricks) to continue the app like your test does.

So it seems that these are two tests are not that related after all, and we might as well keep them separate. I am sorry for the extra work caused by this.

zturner edited edge metadata.Jan 7 2016, 7:34 AM

Linux tests the same functionality in TestBuiltinTrap.py. Would it make sense to merge these two tests, given that the only difference is which compiler intrinsic is used to generate the int3 trap?

Yes, it makes sense to combine the tests. The existing test does use the SB API very well, and TestBuiltinTrap.py is in a Linux-specific part of the test tree, so this may be more of re-working the Linux test to work much like this new one.

Do clang / gcc have an intrinsic to generate an int3?

Linux tests the same functionality in TestBuiltinTrap.py. Would it make sense to merge these two tests, given that the only difference is which compiler intrinsic is used to generate the int3 trap?

Yes, it makes sense to combine the tests. The existing test does use the SB API very well, and TestBuiltinTrap.py is in a Linux-specific part of the test tree, so this may be more of re-working the Linux test to work much like this new one.

Do clang / gcc have an intrinsic to generate an int3?

If not, it would be easy to restore TestBuiltinTrap.py and change my test to use asm ("int 3"); on Linux.

labath added a comment.Jan 7 2016, 7:56 AM

I looked for a while this morning, but I couldn't find any. You can do it with inline asm, but that's about it, I think.

On OS X, there's a "__builtin_debugtrap()" that generates an int3 on x86. That seems more appropriate for this purpose anyway. Don't know whether such a thing exists on Linux, however.

Jim

amccarth updated this revision to Diff 44264.Jan 7 2016, 3:08 PM
amccarth edited edge metadata.

Restored TestBuiltinTrap.py because that's actually for something else.

Changed TestDebugbreak.py to use asm("int3") on non-Windows x86.

I've ordered a Linux box, but I don't currently have one, so I haven't been able to try this on Linux yet.

zturner accepted this revision.Jan 7 2016, 3:26 PM
zturner edited edge metadata.

Windows stuff looks good to me.

This revision is now accepted and ready to land.Jan 7 2016, 3:26 PM
labath accepted this revision.Jan 8 2016, 5:00 AM
labath added a reviewer: labath.

__builtin_debugtrap() indeed works (thanks Jim), but only on clang (no gcc). Since that is architecture-independent, I think we should use that and just make the test @skipIfGcc. Apart from that, the test works fine on linux after fixing the macro issue.

packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile
5

Is anyone actually using icc? I think we should just remove that...

packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
17

I don't think these two XFAILs will be necessary now. Let's assume this will work until proven otherwise.

packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c
5

this will generate the wrong expansion (leaves () hanging). I recommend using the following:
#define BREAKPOINT_INTRINSIC() ...
to make sure the parens are consumed.

amccarth marked 3 inline comments as done.Jan 8 2016, 9:35 AM

Thanks for the Linux check Pavel.

I'm running one last check and then I'll submit and keep an eye on the buildbots for the rest of the day.

packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c
5

Whoops. Nice catch. Thanks.

labath closed this revision.Mar 15 2016, 1:44 AM

This was committed ages ago.