wenmo8 发布的文章

有时,可能需要调试由另一个进程启动的应用程序的启动代码。 这样的示例包括服务和自定义设置操作。 在这些情况下,可以让调试器在应用程序启动时启动并自动附加。

设置应用程序以自动启动调试器

  1. 启动注册表编辑器 (regedit)。

  2. 在“注册表编辑器”中打开 HKEY_LOCAL_MACHINE 文件夹。

  3. 定位到 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options。

  4. 在“Image File Execution Options”文件夹中,找到要调试的应用程序的名称,如 myapp.exe。 如果无法找到要调试的应用程序:


    1. 右击“Image File Execution Options”文件夹,在快捷菜单上单击“新建项”。

    2. 右击新项,然后在快捷菜单上单击“重命名”。

    3. 将项名编辑成您的应用程序的名称;在本示例中为 myapp.exe。

  5. 右击 myapp.exe 文件夹,在快捷菜单上单击“新建字符串值”。

  6. 右击新的字符串值,然后在快捷菜单上单击“重命名”。

  7. 将名称更改为 debugger。

  8. 右击新的字符串值,并在快捷菜单上单击“修改”。

    即显示“编辑字符串”对话框。

  9. 在“数值数据”框中,键入 vsjitdebugger.exe。

  10. 单击“确定”。

  11. 在“注册表”菜单中,单击“退出”。

  12. 包含 vsjitdebugger.exe 的目录必须位于系统路径中。 要将其添加到系统路径,请执行下列步骤:


    1. 以经典视图打开“控制面板”,并双击“系统”。

    2. 单击“高级系统设置”。

    3. 在“系统属性”中,单击“高级”选项卡。

    4. 在“高级”选项卡上,单击“环境变量”。

    5. 在“环境变量”对话框中的“系统变量”下,选择“路径”,然后单击“编辑”按钮。

    6. 在“编辑系统变量”对话框中,将该目录添加到“变量值”框中。 使用分号将它与列表中的其他项隔开。

    7. 单击“确定”关闭“编辑系统变量”对话框。

    8. 单击“确定”关闭“环境变量”对话框。

    9. 单击“确定”关闭“系统属性”对话框。


    现在,使用任意方法启动该应用程序。 Visual Studio 将启动并加载该应用程序。

转储文件(以前称为故障转储)使您能保存程序信息以供以后进行调试。 在没有源文件或符号文件的计算机上测试程序时,转储文件尤其有用。 发生崩溃时,可以先保存转储文件,以后在生成计算机或另一台具有源文件和调试符号的计算机上对其进行调试。

由 Visual Studio 保存和打开的转储文件使用名为小型转储的文件格式。 Visual Studio 可以保存附带或不附带堆信息的小型转储文件。Visual Studio调试器可以保存适用于托管代码或本机代码的小型转储文件。调试器可以加载由 Visual Studio 或由其他以小型转储格式保存文件的程序所创建的转储文件。

创建转储文件

创建和保存转储文件的方法有以下几种:

调试转储

Visual Studio 调试器可以读取包含有关托管代码、非托管代码或二者混合的信息的转储文件。 可以使用普通的调试窗口来同时调试本机转储和托管转储。

转储要求和限制

调试转储文件时,您进行调试的计算机必须能够访问该程序的 PDB 符号文件和二进制文件。 Visual Studio 可以处理某些模块缺少二进制文件的情况,但是必须具有足够的模块以生成有效调用堆栈的二进制。 否则,“模块”窗口中将显示消息“找不到匹配的二进制数”。

对于使用堆保存的小型转储文件,即使未找到应用程序的二进制文件,Visual Studio 也可以加载符号。 小型转储文件,没有需要二进制数以加载符号的堆。 但是,不包含堆的小型转储文件要小得多,如果您有存储或带宽限制,这可以是一个重要的考虑因素。

在 Visual Studio 中,可以使用调试窗口来同时调试本机和托管转储文件。Visual Studio 2008 不支持在调试器窗口中调试托管的代码。 调试托管的小型转储文件需要一个名为 SOS,从“即时”窗口中运行的工具。 在 Visual Studio 中,不再需要 SOS 来调试托管的小型转储文件。

保存和打开转储文件

在 Visual Studio 中,您可以保存来自本机进程或托管进程的转储文件,以便将来再进行调试。 您也可以加载从 Visual Studio 或其他生成转储的实用工具创建的转储文件。

保存转储文件
  1. 在“调试”菜单上,单击“将转储另存为”。

  2. 在“将转储另存为”对话框中,从“保存类型”列表中选择“小型转储”或者“附带堆信息的小型转储”。

    “附带堆信息的小型转储”是 Visual Studio 使用的默认转储格式。 “小型转储”提供的信息较少,但同时需要的空间也较少。

  3. 使用导航控件选择保存位置。

  4. 单击“保存”。

    如果正在调试托管代码,则“将转储另存为”会创建一个托管代码小型转储文件。 如果正在调试本机代码,则“将转储另存为”会创建一个本机代码小型转储文件。 如果正在调试混合的托管代码和本机代码,则“将转储另存为”会创建一个托管代码小型转储文件。

打开转储文件
  1. 在“文件”菜单上,单击“打开”,再单击“文件”。

  2. 在“打开文件”对话框中定位并选择转储文件。

     

    它通常具有 .dmp 扩展名。

  3. 或者在“文件”菜单上,单击“打开”,再单击“文件”。
  4. 单击“确定”。

    将显示“转储文件摘要”窗口。 在该窗口中,您可以查看转储文件的调试摘要信息、设置符号路径、启动调试以及将摘要信息复制到剪贴板中。

  5. 在“操作”部分中,单击“使用‘仅限本机’进行调试”或“使用‘混合模式’进行调试”开始调试。

    为了找到调试转储文件时所需的二进制文件,Visual Studio 会在符号搜索路径中进行查找。 为了确保 Visual Studio 能够找到这些二进制文件,您可以在“选项”对话框或“模块”窗口中添加一个符号搜索路径。

转储模块加载

当您在 Visual Studio 中加载转储文件时,调试器从转储文件所在位置开始查找模块。假设在您创建转储文件时加载了以下二进制文件和模块:

D:\qa\exmpl\exmpl.exe
D:\qa\exmpl\dll.dll
F:\win2k\system32\ntdll.dlll
F:\win2k\system32\kernel32.dll

断点告诉调试器应用程序应该在某个点中断或暂停执行。当中断发生时,程序和调试器被称为处于中断模式。跟踪点是Visual Studio中的一个新调试器功能。跟踪点是具有与其关联的自定义操作的断点。当命中跟踪点时,调试器将执行指定的跟踪点操作,而不是中断程序执行。跟踪点的一个常见用途是在程序到达某个点时打印消息。您可以将跟踪点用于许多与使用跟踪相同的目的,但无需修改代码。另一个区别是,跟踪点只在调试器下运行时工作。

断点概述

断点标志符号

源窗口和反汇编窗口通过在左边距中显示名为glyph的符号来显示断点位置。下表描述了这些标志符号。如果将鼠标放在断点图示符上,则会出现一个断点提示,其中包含更多信息。此信息对于错误和警告断点特别有用。

Glyph

Description

Debug Glyph 1

正常断点。实心标志符号表示断点已启用。空心标志符号表示它已被禁用。

Debug Glyph 2

高级断点。激活/禁用。符号+表示断点至少附加了一个高级功能(如条件、命中计数或筛选器)。

Debug Glyph 3

映射断点。激活/禁用。断点在ASP/ASP.NET代码中设置并映射到相应HTML页面中的断点,或者在服务器端脚本文件中设置并映射到相应的客户端脚本文件。

Debug Glyph 4

追踪点。激活/禁用。达到此点将执行指定的操作,但不会中断程序执行。

Debug Glyph 5

高级跟踪点。激活/禁用。符号+表示跟踪点至少附加了一个高级功能(如条件、命中计数或筛选器)。

Debug Glyph 6

映射跟踪点。激活/禁用。跟踪点在ASP/ASP.NET代码中设置,并映射到相应HTML页面中的跟踪点。

Debug Glyph 7

断点或跟踪点错误。X表示由于错误条件,无法设置断点或跟踪点。

Debug Glyph 8

断点或跟踪点警告。感叹号表示由于临时条件,无法设置断点或跟踪点。通常,这意味着断点或跟踪点位置的代码尚未加载。如果附加到进程并且未加载该进程的符号,则也可以看到。加载代码或符号时,将启用断点并更改图示符

基本断点

最基本的断点是在源代码行或函数上设置的断点。注意:如果一个源文件中有超过64000行代码,则不会命中64000行之后的行上的断点。

一行上有多个断点

有时,一行代码包含多个可执行语句。在这种情况下,可以在行上设置多个断点。包含当前选定断点的代码语句周围将出现一个框。此框可用于区分同一行代码上的多个断点。可以在“断点”窗口中选择断点,也可以单击“源”窗口中包含断点的语句。

高级断点

如果您有VisualC++或VisualStudio,任何版本,您可以设置更高级的断点,创建具有高级特性的断点,并以更强大的方式使用断点。

内存地址和内存更改上的断点

可以在内存地址上设置断点,也就是地址断点。在C/C++中,可以设置一个在内存更改时命中的断点,也就是数据断点(仅限本机)。

筛选、命中计数和条件

过滤器、命中计数和条件是可以附加到任何类型断点(包括跟踪点)的高级功能。

  • 筛选器导致在指定的计算机、进程和线程上设置断点。在调试运行在多个处理器上的应用程序时,筛选器非常有用。
  • 命中计数跟踪断点被命中的次数。默认情况下,断点在每次被命中时都会中断执行。您可以更改此行为,以便只有当命中计数等于或超过指定值或命中计数是给定值的倍数时,断点才会断开。指定的命中计数仅为调试会话保留。
  • 条件是一个表达式,计算该表达式以确定断点是否将断开。

断点限制

在调试混合模式、本机和托管代码时,请避免在系统组件上设置断点。在混合模式调试期间在系统组件上设置断点可能会导致公共语言运行库中断,调试器停止响应。除非您单步执行调用,否则调试器不会自动附加到XML Web服务。这意味着在XML Web服务中设置的任何断点都不会被命中,除非您进入调用。如果尝试使用“开始调试”或“继续”来运行断点,而不是使用“单步执行”,则不会命中断点。

设置简单断点

Visual Studio调试器提供了许多设置断点的方法。下面提供了两种设置简单断点的快速方法。

  • 在快捷菜单上设置简单断点
    在源窗口中,右键单击要设置断点的可执行代码行。在快捷菜单上,单击“断点”,然后单击“插入断点”。
  • 在“调试”菜单上设置简单断点
    在源窗口中,单击要设置断点的可执行代码行。在“调试”菜单上,单击“切换断点”。

设置地址断点

可以在“反汇编”窗口中的内存地址处设置断点。设置断点后,可以在“断点”窗口中编辑地址断点。先转到汇编窗口,然后进行下面的操作:

在“反汇编”窗口中,单击一行代码,然后单击“调试”菜单上的“切换断点”。

-或者-
右键单击一行代码,然后选择“插入断点”。

设置函数断点

可以在函数的开头或函数中的指定位置设置断点。对于脚本,只能在函数的开头设置断点。

  • 插入函数断点
    (可选)在源窗口中,单击函数的名称。这会将函数的名称插入到“新建断点”对话框中,以便您不必键入它。
    在“调试”菜单上,指向“新建断点”,然后单击“函数断点”。

    出现“新建断点”对话框。

    如果“函数”文本框不显示要设置断点的函数的名称,请在“函数”框中键入函数名称,并确保“语言”下拉列表显示该函数的正确编程语言。如果函数未重载,则只需要函数名。对于重载函数,可以指定参数以正确设置断点。键入函数名,后跟括在括号中的参数类型名。例如,对于一个名为a的C#方法,它接受一个带字符串参数和int参数,请键入a(int,string)。
    在本机C++中,可以使用上下文运算符。(仅限Visual Basic和C)如果希望Visual Studio Intellisense验证输入的函数名,请选中“使用Intellisense验证函数名”复选框。
    如果选中该复选框,并且键入的内容与重载签名不匹配,则会出现“选择断点”对话框,您可以选择要放入断点的重载。如果未选中该复选框并键入函数名,则断点将放入所有重载中。如果未选中该复选框,并且键入的签名不匹配,则不会在代码中插入断点。
    断点设置在函数的开头。如果要在函数中的其他位置设置断点,请更改“行”和“字符”框中的值。
    单击“确定”。
  • 从“断点”窗口插入函数断点

    后面的操作跟上面一样。

从调用堆栈窗口设置函数调用的断点

此功能不适用于Transact-SQL、Internet Explorer中的脚本或ASP。本主题描述如何使用调用堆栈窗口在对函数的特定调用上设置断点。断点在函数调用中的下一个可执行指令处设置。如果要在函数本身上设置断点,而不是在对函数的特定调用上设置断点。

在“调用堆栈”窗口中,在中断模式下,右键单击函数调用,然后单击快捷菜单(断点子菜单)上的“插入断点”。断点符号出现在函数调用名称旁边的左边距中。查看断点属性时,此断点显示为地址断点,其内存位置与函数中的下一个可执行指令相对应。

设置数据断点(Native Only)

当写入存储在指定内存位置的值时,数据断点中断执行。如果值是读而不是写的,则执行不会中断。数据断点在以下情况下不起作用:如果未被调试的进程写入内存位置,或者内存位置在两个或多个进程之间共享。如果在内核中更新了内存位置,则数据断点不起作用。例如,如果内存被传递给32位Windows ReadFile函数,则内存将从内核模式更新,并且调试器不会在内存写入时中断。若要设置数据断点,调试器必须仅处于中断模式。变量的地址从一个调试会话更改到下一个调试会话。因此,在每个调试会话结束时,数据断点都会被自动禁用。如果在局部变量上设置了数据断点,则在函数结束时,数据断点将保持启用状态。但是,它设置的内存地址不再具有相同的含义。因此,这种断点的结果是不可预测的。如果在局部变量上设置数据断点,最佳做法是在函数结束之前删除或禁用断点。

Visual Studio 调试器提供了各种用于检查和修改程序状态的工具。 这些工具中的大多数仅在中断模式下有效。

DataTips

数据提示是用于在调试过程中查看程序中的变量和对象的有关信息的最方便工具之一。 在调试器处于中断模式时,可以在当前范围内查看变量的值,方法是将鼠标指针置于源窗口中的变量上。

可视化工具

可视化工具是 Visual Studio 调试器的新组件,通过它可以以有意义的方式查看对象或变量的内容。 例如,可以使用 HTML 可视化工具来查看 HTML 字符串,因为这样可以解释该字符串并在浏览器中显示出来。 您可以通过数据提示、**“监视”窗口、“自动”窗口、“局部变量”窗口或“快速监视”**对话框来访问可视化工具。

变量窗口

可以通过变量窗口来了解变量、寄存器内容和表达式。可以将调试器窗口中使用的数字格式设置为十进制或十六进制。

其他调试器窗口

下面的调试器窗口提供有关程序的重要信息。

表 2

查看

使用

寄存器内容

如何:使用“寄存器”窗口

内存内容

如何:使用“内存”窗口

  • 调用堆栈上的函数名

  • 参数类型

  • 参数值

如何:使用“调用堆栈”窗口

由编译器为程序生成的程序集代码

如何:使用“反汇编”窗口

由您的程序创建线程,即执行的连续流

如何:使用“线程”窗口

程序使用的模块(DLL 和 EXE)

如何:使用“模块”窗口

Visual Studio 调试器包括表达式计算器,当您在**“快速监视”对话框、“监视”窗口或“即时”窗口中输入表达式时,这些计算器可以对其进行计算。 这些表达式计算器还可以在“断点”**窗口和调试器中的许多其他位置使用。

常见的表达式计算器功能

试器中常见的各种表达式计算器功能,这些功能仅因语言不同而不同。

隐式变量

在 Visual Basic 和 C# 中,通过使用表达式计算器可以创建隐式变量。 这些隐式变量永远不会超出范围,可以作为任何其他变量一样处理。在 C# 中,通过在表达式计算器中声明隐式变量可创建隐式变量。 例如,您可以在**“即时”**窗口中输入下列 C# 代码:

int b = 100;

在**“即时”窗口中执行此代码时,新的隐式变量将显示在“局部变量”**窗口中,其变量名称前有一个 $ 符号,在本例中,为 $b。

在 Visual Basic 中,不能在表达式计算器中声明隐式变量。 但是,如果在 Visual Basic 表达式计算器中使用未声明的变量,将会自动创建隐式变量。 在 Visual Basic 中,隐式变量不会列在**“局部变量”**窗口中。

断点

如果使用“即时”窗口计算包含断点的 Visual Basic 或 C# 方法或函数,将命中该断点并在**“调用堆栈”**上显示一个新框架。 下面是一个 C# 示例:

classProgram
{
static void Main(string[] args)
{
//Breakpoint here: int a = 20;
}
}