Visual Studio调试指南---仅调试具有仅我的代码的用户代码

仅我的代码是一种 Visual Studio 调试功能,可自动执行对系统、框架和其他非用户代码的调用。 在 "调用堆栈" 窗口中,仅我的代码将这些调用折叠到 [外部代码] 帧中。在 .NET、 C++和 JavaScript 项目中,仅我的代码的工作方式有所不同。

启用或禁用“仅我的代码”

对于大多数编程语言,默认情况下启用仅我的代码。

  • 若要在 Visual Studio 中启用或禁用仅我的代码,请在 "工具" > 选项"(或"调试 > 选项") >调试 > 常规",选择或取消选择 "启用仅我的代码"。

注意:启用仅我的代码是一项全局设置,适用于所有语言的所有 Visual Studio 项目。

“仅我的代码”调试

在调试会话期间,"模块" 窗口显示调试器将哪个代码模块视为我的代码(用户代码)以及其符号加载状态。 

![模块 窗口中的用户代码](../debugger/media/dbg_justmycode_module.png ""模块" 窗口中的用户代码")

在 "调用堆栈" 或 "任务" 窗口中,仅我的代码将非用户代码折叠成标记为 [External Code] 的灰色批注代码框架。

 

若要查看折叠的 [外部代码] 帧中的代码,请在 "调用堆栈" 或 "任务" 窗口中单击右键,然后从上下文菜单中选择 "显示外部代码"。 展开的外部代码行替换 [外部代码] 框架。

 

在 "调用堆栈" 窗口中双击展开的外部代码行会在源代码中突出显示以绿色显示的调用代码行。 对于 Dll 或未找到或加载的其他模块,可能会打开 "符号或源找不到" 页。

.NET 仅我的代码

在 .NET 项目中,仅我的代码使用符号( .pdb)文件和程序优化来对用户和非用户代码进行分类。 .NET 调试器将优化的二进制文件和非加载 .pdb文件视为非用户代码。

这三个编译器属性还会影响 .NET 调试器认为是用户代码:

  • DebuggerNonUserCodeAttribute 通知调试器,它应用到的代码不是用户代码。
  • DebuggerHiddenAttribute 对调试器隐藏代码,即使“仅我的代码”关闭;
  • DebuggerStepThroughAttribute 通知调试器遍历应用到的代码,而不是单步执行代码。

.NET 调试器将所有其他代码视为用户代码。

在 .NET 调试期间:

  • 调试 > 单步执行(或按F11)在非用户代码上逐过程执行代码,并将代码移到用户代码的下一行。
  • 调试 > 非用户代码上的 "跳出" (或Shift +F11)运行到用户代码的下一行。

如果没有更多的用户代码,调试将继续,直到它结束、到达另一个断点或引发错误。

如果调试器在非用户代码中中断(例如,在非用户代码中使用 "调试" > "全部中断" 和 "暂停"),则不会显示 "无源" 窗口。 然后,你可以使用 "调试 > 步骤" 命令来执行用户代码的下一行。

如果非用户代码中出现未经处理的异常,调试器将在生成异常的用户代码行处中断。

如果对异常启用了第一次机会异常,则调用用户代码行在源代码中以绿色突出显示。 "调用堆栈" 窗口显示标记为 [外部代码] 的带批注的帧。

C++“仅我的代码”

从 Visual Studio 2017 15.8 版开始,还支持代码单仅我的代码。 此功能还要求使用/JMC (仅我的代码调试)编译器开关。 默认情况下,在项目中C++启用此开关。 对于 "调用堆栈" 窗口和仅我的代码中的调用堆栈支持,不需要/JMC 开关。

若要归类为用户代码,必须由调试器加载包含用户代码的二进制文件的 PDB (使用 "模块" 窗口进行检查)。

对于调用堆栈行为(如 "调用堆栈" 窗口中的), C++中的仅我的代码仅将这些函数视为非用户代码:

  • 在其符号文件中去除了源信息的函数。
  • 符号文件指示没有对应于堆栈帧的源文件的函数。
  • %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers文件夹中 * natjmc文件中指定的函数。

对于代码单步执行行为, C++仅我的代码仅将这些函数视为非用户代码:

  • 调试器中尚未加载相应的 PDB 文件的函数。
  • %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers文件夹中 * natjmc文件中指定的函数。

为了仅我的代码中的代码步进支持C++ ,必须在 Visual Studio 15.8 Preview 3 或更高版本中使用 MSVC 编译器来编译代码,并且必须启用/JMC 编译器开关(默认情况下启用)。 对于使用较旧的编译器编译的代码, . natstepfilter files 是自定义代码单步执行的唯一方法,该方法与仅我的代码无关。

调试C++期间:

  • 调试 > 单步执行(或按F11)在非用户代码上逐过程执行代码,并将代码移到用户代码的下一行。
  • 调试 > 非用户代码上的 "跳出" (或Shift +F11)运行到用户代码的下一行。

如果没有更多的用户代码,调试将继续,直到它结束、到达另一个断点或引发错误。

如果调试器在非用户代码中中断(例如,在非用户代码中使用 "调试" > "全部中断" 和 "暂停"),则在非用户代码中继续执行。

如果调试器遇到异常,则它会在异常上停止,无论它是在用户代码还是非用户代码中。 "异常设置" 对话框中的用户未处理的选项将被忽略。

自C++定义调用堆栈和代码单步执行行为

对于C++项目,可以指定模块、源文件和函数,"调用堆栈" 窗口将其视为非用户代码,方法是在 * natjmc文件中指定它们。 如果使用的是最新的编译器,此自定义也适用于代码单步执行(请参阅 C++仅我的代码)。

  • 若要为 Visual Studio 计算机的所有用户指定非用户代码,请将natjmc文件添加到 %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers文件夹。
  • 若要为单个用户指定非用户代码,请将natjmc文件添加到 %USERPROFILE%\My 文档 \ < Visual Studio 版本 > \visualizers文件夹中。

Natjmc文件是具有以下语法的 XML 文件:

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>

模块元素属性

表 1
特性描述
Name 必须的。 模块的完整路径。 可以使用 Windows 通配符 ? (零个或一个字符)和 * (零个或多个字符)。 例如,应用于对象的

<Module Name="?:\3rdParty\UtilLibs\*" />

告知调试器中的所有模块都视为 \3rdParty\UtilLibs 外部代码的任何驱动器上。
Company 可选。 发布在可执行文件中嵌入的模块的公司的名称。 可以使用此特性消除模块歧义。

文件元素属性

表 2
特性描述
Name 必须的。 要视为外部代码的源文件的完整路径。 可以在指定路径时使用 Windows 通配符 ?*

函数元素属性

表 3
特性描述
Name 必须的。 要视为外部代码的函数的完全限定的名称。
Module 可选。 包含函数的模块的名称或完整路径。 可以使用此特性区分具有相同名称的函数。
ExceptionImplementation 设置为 true 时,调用堆栈显示的是引发异常的函数,而不是此函数。

自C++定义独立于仅我的代码设置的单步执行行为

在C++项目中,可以通过将函数作为 * 文件中的非用户代码列出来指定要逐过程执行的函数。 *@No__t_1*文件中列出的函数不依赖于仅我的代码设置。

  • 若要为所有本地 Visual Studio 用户指定非用户代码,请将natstepfilter文件添加到 %VsInstallDirectory%\Common7\Packages\Debugger\Visualizers文件夹。
  • 若要为单个用户指定非用户代码,请将natstepfilter文件添加到 %USERPROFILE%\My 文档 \ < Visual Studio 版本 > \visualizers文件夹中。

Natstepfilter文件是具有以下语法的 XML 文件:

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>

 

表 4
元素描述
Function 必须的。 将一个或多个函数指定为非用户函数。
Name 必须的。 ECMA-262 格式的正则表达式,指定要匹配的完整函数名。 例如:

<Name>MyNS::MyClass.*</Name>

告知调试器将 MyNS::MyClass 中的所有方法都视为非用户代码。 匹配区分大小写。
Module 可选。 ECMA-262 格式的正则表达式,指定包含函数的模块的完整路径。 匹配不区分大小写。
Action 必须的。 以下区分大小写的值之一:

NoStepInto-通知调试器逐过程执行该函数。
StepInto-通知调试器单步执行函数,并重写匹配函数的任何其他 NoStepInto

posted on 2020-03-16 09:27  活着的虫子  阅读(4088)  评论(0编辑  收藏  举报

导航