Break on thread creation in Visual Studio debugger

2020-06-17 05:40发布

问题:

Can I set the Visual Studio debugger to break on thread creation?

(Note this is not the same as breaking on context switch as asked for in this other question: Can I set a breakpoint in Visual Studio (c++) to break on a thread context switch?)

回答1:

I've found a way to do it. While googling I saw the opposite question: Is it possible to break on thread exit with specific error code?

I put a breakpoint at the function RtlExitUserThread, after that I realized that all threads was creating with the function RtlUserThreadStart, so put another breakpoint to that function and that's all :)



回答2:

If you know the thread is being created by the managed Thread class, then a simple solution would be to put a breakpoint on its entry (by going to the Breakpoints window, clicking New->Break at function and marking Thread.Start).

Otherwise, as Hans said, you would have to use a more complex solution like mdbg, or using a open-source implementation of CLR profiler (like SAE) and putting an "asm int 3" instruction in the ICorProfilerCallback::ThreadCreated method.

Also, if you have VS2010 Ultimate, you could just look up the Thread Created event in Intellitrace events, and possibly get the information you need from there (though this will not break when the thread is created, but rather give you some info about the stack trace/variable values at the time it was created, in retrospect).



回答3:

Yes, the debugger gets a notification for it. No, the UI doesn't allow you to tell it to break on that notification. If this is for managed code then you could use the MDbg sample and modify it.



回答4:

As explained by @George, there are two functions you can break on. If you want to find out what creates the new thread you should break on thread creating WINAPI function calls such as CreateThread or _beginthread(ex). If you want to break into the start of the newly created thread (on the call stack of that thread itself) you should break into RtlUserThreadStart.

However, there are two prerequisites to be able to break into either of these:

1. Symbol downloading from Microsoft Servers needs to be enabled

For the breakpoints to work the debugger needs to know some basic symbol information of the native dlls. Make sure symbol loading from MS servers is enabled (Tools -> Options -> Debugging -> Symbols)

2. You need the actual stdcall signatures of the target functions

For some reason even with enabled export loading VS was unable to find the functions I needed to break on for me. So I went checking what the actual signatures are. This can be done by using the dumpbin cmd line tool of VS, or by running a short test on the code:

void* ptr = CreateThread;

Running this code in the debugger reveals the address and signature of the CreateThread for example which is _CreateThreadStub@24 for me (Win7 32-bit application). For RtlUserThreadStart it was ___RtlUserThreadStart@8 for me.

3. Setting the breakpoint

Now it's as easy as choosing Debug -> New Breakpoint -> Break at Function. For the function name you put either _CreateThreadStub@24 or ___RtlUserThreadStart@8 and leave the rest be.

This then triggers when a new thread is being created.

Observation

_CreateThreadStub@24 seems to cover the CreateThread, _beginthread and _beginthreadex functions.



回答5:

There are at least 2 potential things you could mean when you say you want to break on thread creation:

  1. Break inside the creating thread BEFORE the new thread has been created
  2. Break inside the NEW thread before the user-provided function is called.

For the first option, you'll want to break in CreateThread, _beginthread, or _beginthreadex.

For the second option, you'll want to break in RtlUserThreadStart or BaseThreadInitThunk to catch the new thread early in its execution before user code gets called.

Unfortunately, Visual studio won't break in those functions if you create a breakpoint with the function names I've listed above, at least not by default. The problem is that for native debugging, it doesn't load DLL exports by default, and without that, the debugger has no idea where to find the names I've provided above.

Before you start debugging, in Visual Studio go to tools, options, debugging, then expand the debugging options tree in the left pane. Then click on "native" and check "Load DLL Exports". Then you can start debugging your executable again.

After that, you should be able to create a breakpoint on any of the functions I mentioned by typing in the name. You may or may not need to specify the DLL the function is in by creating the breakpoint with the name as follows:

{,,kernel32.dll}CreateThread

or

{,,ntdll.dll}RtlUserThreadStart

I got this information by starting here:

https://blogs.msdn.microsoft.com/reiley/2011/07/26/debugging-tips-for-multi-threaded-application/

and doing some experimenting on my own. I know this is a response to an old question but I hope this saves other people some of the pain I've had when trying to debug crashes that happen immediately upon thread startup.



回答6:

You can set a breakpoint at the first call to CreateThread (maybe you insert a fake call for this purpose). When hit, change from Source Code View to Disassemly View and step into the call. Go through the ImportLib-Code and set a breakpoint. Not perfect, but it works.