调试 MFC header 代码不适用于 Visual Studio 2019

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

TL;DR:将 调试到 MFC (CString) header 代码在 我的机器,据我所知,这是由于这些 header 的特殊编译方式造成的。

通过反汇编输入时单步执行 MFC header 代码有效,但设置 brealpoints 无效。

我正在寻找解决方法或至少是对我的分析的认可。


系统:

设置:(我很抱歉这太长了。)

现在,您可以在调试器下启动程序,您应该在第一个断点处停止:

现在,确保所有符号都已加载,最简单的方法是通过调用堆栈完成:

只是 select 调用堆栈中的所有行 window 并点击上下文菜单中的加载符号。之后调用堆栈应该大致如下所示:

     >  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

现在,您可以尝试 stepping-into(可能是 F11)CWinAppEx::InitInstance() 功能,它应该 工作 没问题,让你进入 mfc140ud.dll!CWinApp::InitInstance() Line 394 - 没关系。

再次走出去,然后尝试 step-into CString ctor:

这在我的机器上不起作用!

然而,我能做的是(从上面的观点)切换到反汇编视图,进入那里的 calls 并以这种方式进入 header 代码:

然后我可以成功单步执行(但永远不会进入)MFC header 代码。尝试设置断点将导致错误:

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 Studio19\Professional\VC\Tools\MSVC.28.29910\atlmfc\include\cstringt.h

这就是我所在的位置。

分析:

我们从 MFC 代码中可以看出,我们 可以 进入“常规”cpp 代码,但是一旦我们尝试进入(或设置断点)代码在里面 CStringt.h 它坏了。

这里很特别:这是模板 header 代码,执行的代码(如反汇编所示)仍然不在用户模块中,而是在 mfc###.dll!我认为他们对预处理器做了一些巧妙的技巧(参见 defined(_MFC_DLL_BLD) 等),这使得 header 文件可以被多次使用,也许这也是破坏调试器的原因。

问题:

这里最有趣的答案实际上是关于为什么会中断 - 调试器在哪里混淆?这是调试库代码时重新define-ing 代码的普遍问题吗?

取消选中“工具”->“选项”->“调试”中的“仅启用我的代码”选项

我知道这适用于 c++ std:: 库代码调试。当我忘记取消选中此选项时,我使用的另一种技术与您上面描述的类似。

  1. 在我要进入的代码行设置断点。
  2. 到达断点后,右键单击编辑器window和select“Go To Disassemly”。
  3. 在反汇编模式下,单步执行直到到达 call 语句。这通常是 std 库。最终,您将导航到汇编和系统代码源的混合体。您可以通过再次右键单击并selecting“转到源代码”来退出反汇编模式。

MSVC 附带的源不匹配。

我认为会发生这种情况,因为 DLL 使用 Windows 更新或新的 vcredist 进行了更新,但 Visual Studio 包含未更新。如果您使用 /MT/MTd 和 link MFC 静态构建,问题不会持续存在。

如果您关心,可能可以将此报告给 http://developercommunity.visualstudio.com

解决方法 1

执行@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".

(跳过与本期无关的部分)

然后手动拾取header的位置,调试器会告诉它不匹配。虽然差异似乎微不足道,所以 header 是可用的。

解决方法 2

Link MFC 静态,用/MT/MTd

编译

解决方法 3

ATL 有一个类似的 CString 没有遇到这个问题:

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

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

分析在某些时候出现了问题,但我们终于在这里找到了问题的一部分:

Require source files to exactly match the original version选项:

是问题所在,但以一种非常奇特的方式:

当您不需要匹配源文件(即禁用此默认选项)时,OP 的错误行为就会发生:调试器无法再将符号与 cstringt.h 文件匹配。

不幸的是,我在两台机器上都禁用了这个。拉入第三台机器显示我们可以设置断点(尽管 F11 仍然不起作用)并且通过比较 VS 设置的 xml 导出我们发现这是不同的。

所以,长话短说:对于我们来说,要能够在(未修改的!)MFC header 中设置断点,需要我们启用 Require source files to exactly match ..选项。

如果该选项被禁用,这意味着调试器会采取更宽松的行为,它将不再有效。

而且,是的,我们仔细检查了它始终是相同的源文件 C:\Program Files (x86)\Microsoft Visual Studio19\Professional\VC\Tools\MSVC.28.29910\atlmfc\include\cstringt.h

step-into/F11 的谜团仍然存在,但我想这最好单独提出一个问题。