Martin Ba
Martin Ba

Reputation: 38766

Debugging into MFC header code does not work with Visual Studio 2019

TL;DR: Debuigging into MFC (CString) header code does not work on both my machines and as far as I can tell this is due to the peculiar way these headers are compiled.

Stepping through MFC header code when entered via disassembly works, but setting brealpoints does not work.

I'm looking for a workaround or at least acknowledgement of my analysis.


System:

Setup: (I do apologize for this being rather long.)

Now, you can start the program under the debugger, and you should stop at the first breakpoint:

First breakpoint in InitInstance

Now, make sure all symbols are loaded, easiest done via the Call Stack:

Fully selected Call Stack with Context Menu and marked Load Symbols entry

Just select all lines in the call stack window and hit Load Symbols in the context menu. Afterwards the call stack should look roughly like this:

     >  MFCApplication1.exe!CMFCApplication1App::InitInstance() Line 75 C++
        mfc140ud.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 37    C++
        MFCApplication1.exe!wWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 26   C++
        MFCApplication1.exe!invoke_main() Line 123  C++
        MFCApplication1.exe!__scrt_common_main_seh() Line 288   C++
        MFCApplication1.exe!__scrt_common_main() Line 331   C++
        MFCApplication1.exe!wWinMainCRTStartup(void * __formal=0x000000c2b7084000) Line 17  C++
        kernel32.dll!BaseThreadInitThunk()  Unknown
        ntdll.dll!RtlUserThreadStart()  Unknown

Now, you can try stepping-into (possibly F11) the CWinAppEx::InitInstance() function, which should work without a problem, landing you in mfc140ud.dll!CWinApp::InitInstance() Line 394 - this is OK.

Step out again, and then then try to step-into the CString ctor:

Breakpoint at CString ctor

This DOES NOT work on my machine(s)!

What I can do however, is (from the point above) switch to disassembly view, step into the calls there and get into the header code this way:

Disassembly step into MFC header copde

I can then successfully step through (but never into) the MFC header code. Trying to set a breakpoint will result in the error:

The breakpoint will not currently be hit. No executable code of the debugger's code type is associated with this line. Possible causes include ...

C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h

Breakpoint error

And this is where I'm at.

Analysis:

What we can see from the MFC code is that we can step into "regular" cpp code, but as soon as we try to step into (or set breakpoint) code that is inside this CStringt.h it breaks.

Peculiar here: This is template header code, and still the executed code (as shown by the disassembly) is not in the user module but in the mfc###.dll! I think they do some clever tricks with the preprocessor (see defined(_MFC_DLL_BLD) and somesuch) which enables this multi use of the header file, and maybe, possibly this is also what breaks the debugger.

Question:

The most interesting answer here would actually be as to WHY this breaks - where does the debugger get confused? Is this a general problem with re-define-ing code when debugging library code?

Upvotes: 4

Views: 1137

Answers (4)

David V. Corbin
David V. Corbin

Reputation: 397

NOTE: The "difference" are NOT just tied to CString... I am aving the same type of problem [with VS-2019 and latest updates] string to step into CDialog::DoModal()...

With the "Exact match" disabled, it steps to some 'random line'... with it enabled it prompts for a source file....

So how do we get these to MATCH??/

Upvotes: 0

Alex Guteniev
Alex Guteniev

Reputation: 13634

The source shipped with MSVC does not match.

I think this happen, as DLLs got updated with Windows Update or a new vcredist, but Visual Studio includes are not updated. If you build with /MT or /MTd and link MFC statically, the problem does not persist.

Probably this can be reported to http://developercommunity.visualstudio.com if you care.

Workaround 1

Do steps described by @selbie:

  1. Set a breakpoint on the line of code I want to step into.
  2. When the breakpoint is reached, right click in the editor window and select "Go To Disassemly".
  3. In disassembly mode, step over until you get to a call statement. [...] You can flip out of disassembly mode by right-clicking again and selecting "go to source code".

(skipped the part not relevant to this issue)

Then pick up the location of the header manually, the debugger will tell that it does not match. The difference seem to be insignificant though, so the header is usable.

Workaround 2

Link MFC statically, compile with /MT or /MTd

Workaround 3

ATL has a similar CString that does not suffer from the issue:

#include <atlbase.h>
#include <atlstr.h>

int main() {
    ATL::CString this_is_text("Debugging into CString header works");
}

Upvotes: 3

Martin Ba
Martin Ba

Reputation: 38766

Analysis went sideways at some point, but we finally found one part of the problem here:

The Require source files to exactly match the original version option:

Debugging General Option

was the problem, but in a very peculiar way:

When you do NOT require source files to match (that is, disable this default option), then the erroneous behavior of the OP occurs: The debugger can no longer match the symbols to the cstringt.h file.

Unfortunately, I had this disabled on both machines. Pulling in a third machine showed that we could set breakpoints (though F11 still does not work) and by comparing the xml export of the VS settings we found that this was different.

So, long story short: For us, to be able to set breakpoints in the (unmodified!) MFC header, requires us to enable the Require source files to exactly match .. option.

If the option is disabled, which would imply a more lenient behavior by the debugger, it no longer works.

And, yes, we double checked it's always the same source file at C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h

The mystery with step-into/F11 persists, but I guess this would better be taken to a separate question.

Upvotes: 4

selbie
selbie

Reputation: 104474

Uncheck the Enable Just My Code option in Tools->Options->Debugging

enter image description here

I know that works for c++ std:: library code debugging. The other technique I do, when I forget to uncheck this option, is similar to what you describe above.

  1. Set a breakpoint on the line of code I want to step into.
  2. When the breakpoint is reached, right click in the editor window and select "Go To Disassemly".
  3. In disassembly mode, step over until you get to a call statement. That's typically the std library. Eventually, you'll navigate into a mix of assembly and system code sources. You can flip out of disassembly mode by right-clicking again and selecting "go to source code".

Upvotes: 0

Related Questions