使用“仅我的代码”仅调试用户代码
仅我的代码 是一项 Visual Studio 调试功能,可自动逐步执行对系统、框架和其他非用户代码的调用。 在 调用堆栈 窗口中,Just My Code 会将这些调用折叠到 [外部代码] 帧中。
在 .NET 和 C++ 项目中,“仅我的代码”的工作方式不同。
启用或禁用“仅我的代码”
对于大多数编程语言,默认启用“仅我的代码”。
- 若要在 Visual Studio 中启用或禁用“仅我的代码”,请在“工具>选项”(或“调试>选项)>调试>常规下,选择或取消选择 启用”仅我的代码“。
说明
启用“仅我的代码” 是一个全局设置,适用于所有语言的所有 Visual Studio 项目。
“仅我的代码”调试
在调试会话期间,“模块”窗口显示调试器将视为“我的代码”(用户代码)及其符号加载状态的代码模块。 有关详细信息,请参阅熟悉调试器如何附加到应用。
在 调用堆栈 或 任务 窗口中,“仅我的代码”会将非用户代码折叠为标记为 [External Code]
的灰色批注代码框架。
提示
若要打开 模块、调用堆栈、任务或其他大多数调试窗口,必须位于调试会话中。 调试时,在“调试>Windows”下,选择要打开的窗口。
若要查看折叠 [外部代码] 框架中的代码,请在 调用堆栈 或 任务 窗口中右键单击,然后从上下文菜单中选择 显示外部代码。 扩展的外部代码行替换 [外部代码] 帧。
说明
“显示外部代码”是当前用户探查器设置,会应用于用户打开的所有语言的全部项目。
双击“调用堆栈”窗口中展开的外部代码行,将在源代码中以绿色突出显示调用代码行。 对于 DLL 或其他未找到或未加载的模块,可能会打开“找不到符号或源代码”页面。
从 Visual Studio 2022 版本 17.7 开始,可以通过在“调用堆栈”窗口中双击外部代码来自动编译 .NET 代码。 有关详细信息,请参阅 调试时从 .NET 程序集生成源代码。
.NET“仅我的代码”
在 .NET 项目中,Just My Code 使用符号(.pdb) 文件和程序优化来对用户和非用户代码进行分类。 .NET 调试器将优化的二进制文件和非加载 .pdb 文件视为非用户代码。
三个编译器属性还影响 .NET 调试器视为用户代码的内容:
- DebuggerNonUserCodeAttribute 告知调试器应用的代码不是用户代码。
- DebuggerHiddenAttribute 会隐藏调试器中的代码,即使关闭了“仅我的代码”选项也是如此。
- DebuggerStepThroughAttribute 告知调试器单步跳过而不是单步调试应用它的代码。
.NET 调试器将所有其他代码视为用户代码。
在 .NET 调试期间:
- 对非用户代码执行“调试”>“单步调试”(或 F11)会单步跳过该代码,转到下一行用户代码。
- 对非用户代码执行“调试”>“单步跳出”(或 Shift+F11)会运行到下一行用户代码。
如果没有更多用户代码,调试会继续进行,直到遇到另一个断点、引发错误或结束。
如果调试器在非用户代码中中断(例如,使用 调试>中断所有 并在非用户代码中暂停),则将显示 “无源”窗口。 然后,可以使用 调试>步骤 命令转到下一行用户代码。
如果在非用户代码中发生未经处理的异常,调试器将在生成异常的用户代码行处中断。
如果针对异常启用了第一机会异常,则在源代码中以绿色突出显示调用用户代码行。 调用堆栈 窗口显示一个标注为 [外部代码]的框架。
C++“仅我的代码”
从 Visual Studio 2017 版本 15.8 开始,还支持使用“仅我的代码”来单步执行代码。 此功能还要求使用 /JMC(仅我的代码调试)编译器开关。 默认情况下,该开关在C++项目中启用。 对于“仅我的代码”中的“调用堆栈”窗口和调用堆栈支持,不需要 /JMC 开关。
要归类为用户代码,调试器必须加载包含用户代码的二进制文件的 PDB(使用 Modules 窗口检查加载状态)。
对于调用堆栈行为(例如在“调用堆栈”窗口中),C++中的“仅我的代码”功能将这些函数视为 非用户代码:
- 在其符号文件中去除了源信息的函数。
- 函数的符号文件显示,没有与堆栈帧对应的源文件。
- %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers 文件夹中的 *.natjmc 文件中指定的函数。
对于代码单步执行行为,C++ 中的“仅我的代码”仅将以下函数视为非用户代码:
- 未在调试器中加载相应 PDB 文件的函数。
- %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers 文件夹中的 *.natjmc 文件中指定的函数。
说明
对于“仅我的代码”中的代码单步执行支持,必须使用 Visual Studio 15.8 预览版 3 或更高版本中的 MSVC 编译器编译C++代码,并且必须启用 /JMC 编译器开关(默认情况下已启用)。 有关其他详细信息,请参阅 自定义 C++ 调用堆栈和代码单步执行行为,此 博客文章。 对于使用较旧的编译器编译的代码,.natstepfilter 文件是自定义代码单步执行的唯一方法,这与“仅我的代码”无关。 请参阅自定义 C++ 单步执行行为。
- 如果从非用户代码调用“单步执行”,则对非用户代码执行“调试”>“单步执行”(或 F11)会逐过程执行该代码,或运行到下一行用户代码。
- 对非用户代码执行“调试”>“单步跳出”(或 Shift+F11)会运行到下一行用户代码(当前堆栈帧外部)。
如果没有更多的用户代码,调试会一直持续下去,直到结束、遇到另一个断点或者引发错误。
如果调试器在非用户代码中中断(例如,使用“调试”>“全部中断”在非用户代码中暂停),则会继续在非用户代码中单步执行。
如果调试器遇到异常,它将停止在异常位置,无论该异常是在用户代码中还是非用户代码中。 忽略 异常设置 对话框中用户未经处理的 选项。
自定义C++调用堆栈和代码单步执行行为
对于 C++ 项目,可以指定“调用堆栈”窗口视为非用户代码的模块、源文件和函数,方法是在 *.natjmc 文件中进行指定。 如果使用最新的编译器,则此自定义也适用于代码单步执行(请参阅 C++“仅我的代码”)。
- 若要为 Visual Studio 计算机的所有用户指定非用户代码,请将 .natjmc 文件添加到 %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers 文件夹中。
- 若要为单个用户指定非用户代码,请将 .natjmc 文件添加到 %USERPROFILE%\My Documents\<Visual Studio 版本>\可视化工具 文件夹中。
.natjmc 文件是一个具有以下语法的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<NonUserCode xmlns="http://schemas.microsoft.com/vstudio/debugger/jmc/2015">
<!-- Modules -->
<Module Name="ModuleSpec" />
<Module Name="ModuleSpec" Company="CompanyName" />
<!-- Files -->
<File Name="FileSpec"/>
<!-- Functions -->
<Function Name="FunctionSpec" />
<Function Name="FunctionSpec" Module ="ModuleSpec" />
<Function Name="FunctionSpec" Module ="ModuleSpec" ExceptionImplementation="true" />
</NonUserCode>
模块元素属性
属性 | 描述 |
---|---|
Name |
必填。 模块的完整路径。 可以使用 Windows 通配符 ? (零或一个字符)和 * (零个或多个字符)。 例如<Module Name="?:\3rdParty\UtilLibs\*" /> 告知调试器将任何驱动器上 \3rdParty\UtilLibs 中的所有模块视为外部代码。 |
Company |
自选。 发布嵌入在可执行文件中的模块的公司的名称。 可以使用此属性消除模块的歧义。 |
文件元素属性
属性 | 描述 |
---|---|
Name |
必填。 要视为外部代码的源文件的完整路径。 指定路径时,可以使用 windows 通配符 ? 和 * 。 |
函数元素属性
属性 | 描述 |
---|---|
Name |
必填。 要视为外部代码的函数的完全限定的名称。 指定路径时,您可以使用 Windows 通配符 ? 和 * 。 |
Module |
自选。 包含函数的模块的名称或完整路径。 可以使用此属性消除同名函数的歧义。 |
ExceptionImplementation |
设置为 true 时,调用堆栈将显示引发异常的函数,而不是此函数。 |
独立于“仅我的代码”设置自定义 C++ 单步执行行为
在C++项目中,可以通过在 *.natstepfilter 文件中将它们列为 NoStepInto 函数,来指定要跳过的函数。 *.natstepfilter 文件中列出的函数不依赖于“仅我的代码”设置。 NoStepInto 函数告知调试器跳过该函数,即使它调用了一些 StepInto 函数或其他用户代码。 与 .natjmc中列出的函数不同,调试器将单步执行 NoStepInto 函数中的第一行用户代码。
- 若要为所有本地 Visual Studio 用户指定非用户代码,请将 .natstepfilter 文件添加到 %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers 文件夹中。
- 若要为单个用户指定非用户代码,请将 .natstepfilter 文件添加到 %USERPROFILE%\My Documents\<Visual Studio 版本>\可视化工具 文件夹中。
说明
某些第三方扩展可能会禁用 .natstepfilter 功能。
.natstepfilter 文件是具有以下语法的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<StepFilter xmlns="http://schemas.microsoft.com/vstudio/debugger/natstepfilter/2010">
<Function>
<Name>FunctionSpec</Name>
<Action>StepAction</Action>
</Function>
<Function>
<Name>FunctionSpec</Name>
<Module>ModuleSpec</Module>
<Action>StepAction</Action>
</Function>
</StepFilter>
元素 | 描述 |
---|---|
Function |
必填。 将一个或多个函数指定为非用户函数。 |
Name |
必填。 ECMA-262 格式的正则表达式,指定要匹配的完整函数名称。 例如:<Name>MyNS::MyClass::.*</Name> 告知调试器 MyNS::MyClass 中的所有方法都被视为非用户代码。 匹配区分大小写。 |
Module |
自选。 ECMA-262 格式的正则表达式,指定包含函数的模块的完整路径。 匹配不区分大小写。 |
Action |
必填。 以下区分大小写的值之一:NoStepInto - 告知调试器跳过函数。StepInto - 告知调试器单步调试函数,为匹配的函数重写任何其他 NoStepInto 。 |
有关 .natstepfilter 和 .natjmc 文件的其他信息
从 Visual Studio 2022 版本 17.6 开始,可以将 .natjmc 和 .natstepfilter 文件直接添加到解决方案或项目中。
调试器的“输出”窗口中未报告 .natstepfilter 和 .natjmc 文件中的语法错误。
与 .natvis 文件不同,.natstepfilter 和 .natjmc 文件不会热重载。 相反,这些文件将在调试会话开始时重新加载。
对于模板函数,在名称中使用
<.*>
或<.*
可能很有帮助。
JavaScript 仅我的代码
Visual Studio 2022 中的 .esproj 项目,Visual Studio Code 使用 launch.json 文件来配置和自定义调试器。 launch.json 是调试器配置文件。
Visual Studio 仅将调试器附加到用户代码。 对于 .esproj 项目,可以使用 launch.json 中的 skipFiles
设置在 Visual Studio 中配置用户代码(即“仅我的代码”设置)。 此设置的工作方式与 VS Code 中的 launch.json 设置相同。 有关 skipFiles的详细信息,请参阅跳过不感兴趣的代码。