This is an archive of the discontinued LLVM Phabricator instance.

Enable debugging of multithreaded programs on Windows.
ClosedPublic

Authored by amccarth on May 13 2015, 10:22 AM.

Details

Reviewers
zturner
Summary

Rewrote test app to use std::thread instead of pthreads because Windows doesn't have pthreads. This involved changing it from a C application to a C++ application.

Added missing code in HandleCreateThreadEvent and HandleExitThreadEvent to actually track the threads.

Modified ExceptionRecord to keep track of the ID of the thread that caused the exception. This resolves the discrepancy between the PC and the breakpoint address in the exception record, which allows the code to find the breakpoint that was hit and thus recognizes that the thread needs stop info.

Changed ProcessWindowsData::m_exited_threads to be just a set of thread IDs, since there are no HostThread objects to map to for threads that are gone.

Fixed some of the logging in ProcessWindows (like the order of some parameters and more consistent use of hexadecimal for thread IDs).

Fixed crash in ProcessWindows::OnExitThread when terminating a multi-threaded inferior.

Plumbed through the exit code for a thread, but not actually using it yet.

Diff Detail

Event Timeline

amccarth updated this revision to Diff 25706.May 13 2015, 10:22 AM
amccarth retitled this revision from to Enable debugging of multithreaded programs on Windows..
amccarth updated this object.
amccarth edited the test plan for this revision. (Show Details)
amccarth added a reviewer: zturner.
amccarth added a subscriber: Unknown Object (MLST).
zturner edited edge metadata.May 13 2015, 10:33 AM

Awesome! going to take a look in a little bit. Does this cause any tests to pass that previously failed? If so, how many?

Looks good, just some minor changes and this should be good to go.

source/Plugins/Process/Windows/ExceptionRecord.h
33

You can probably make this a DWORD. We need to use the lldb types whenever it's somethign that's exposed from the plugin through an API, or when it's in some code that otherwise needs to have a stable interface among different platforms. But for internal types we should be using the native OS types. lldb::tid_t and pid_t are both 64 bits I think, and process / thread ids are 32 bits on windows, so there's ugly casting going on at every call site if we use the lldb public types internally.

(Also feel free to fix up any instances of this where I didn't follow my own rule)

source/Plugins/Process/Windows/ProcessWindows.cpp
437

consider using lldbassert() here. In Debug mode it is equivalent to assert(), but in release mode it will print a stack trace and continue on instead of doing nothing. See Utility/LLDBAssert.h.

775

Generally prefer to invert conditionals and early-out to keep indentation low. So change this to

if (!m_session_data)
    return;

It looks like this might have exposed a couple of latent test failures, so I'm looking at those now:

Two other tests are occasionally crashing because they're getting debug events for new threads after the session data has been cleaned up.

source/Plugins/Process/Windows/ExceptionRecord.h
33

I saw the the exception address was saved as an lldb::addr_t and figured that I should do the same in case we ever need to pass these values to platform-independent APIs. There's no casting caused by my case, since lldb::tid_t is large enough to handle the thread IDs from any platform, which I assumed was by design.

Using DWORD consistently internally requires including <windows.h> in more headers (like IDebugDelegate.h and LoadDebugDelegate.h), which I'm hesitant to do since the Windows headers aren't well-behaved.

source/Plugins/Process/Windows/ProcessWindows.cpp
437

I've actually removed the assert altogether (as was originally my intent). I put it there to assure myself that we were getting the correct stop thread (which we are now) and to convince myself that your TODO was unnecessary.

775

Done under protest.

Generally speaking[1], I'm not a fan of conditional returns in the middle of a function. And this can't be moved to the top of the function like a true guard clause, because it must be done under the lock.

It reverses the natural logic of checking a prerequisite before doing a condition. Checking prerequisites is a way to avoid excessive indentation without introducing exit points in the middle of a function.

[1]: There are appropriate times to return from the middle of a function, but I don't feel this is one of them.

amccarth updated this revision to Diff 25804.May 14 2015, 1:16 PM
amccarth edited edge metadata.

I'm not convinced that the intermittent test crash on Windows (in TestWatchpointSetErrorCases) is related to this change. I'd like to get this submitted and continue to debug the crash as a separate effort.

sounds good.

amccarth updated this revision to Diff 26015.May 18 2015, 2:34 PM

This is just the Windows-specific portion of this patch.

My attempt to commit the entire patch was rolled back because converting the inferior for TestNumThreads.py from pthreads to std::thread somehow caused it to fail on Linux (but not Mac or Windows). I'm still investigating the root cause of that. In the mean time, I'd like to land the Windows-specific part of the changes.

zturner accepted this revision.Oct 15 2015, 1:46 PM
zturner edited edge metadata.
This revision is now accepted and ready to land.Oct 15 2015, 1:46 PM
Eugene.Zelenko added a subscriber: Eugene.Zelenko.

Committed in r237392.