wenmo8 发布的文章

Visual Studio 调试器提供了功能强大的命令来控制应用程序的执行。 下面描述了为控制执行利用调试器命令可执行的任务:

  • 开始(或继续)执行

  • 中断执行

  • 停止执行

  • 逐句通过应用程序

  • 运行到指定的位置

  • 设置执行点

开始执行

开始执行是最基本的调试功能之一。

  1. 在“调试”菜单上选择“开始”、“逐语句”或“逐过程”。

    - 或 -

  2. 在源窗口中,右击可执行代码中的某行,然后选择“运行到光标处”。

如果选择“启动”,则应用程序启动并一直运行到断点。 可以在任何时刻中断执行,以检查值,修改变量,或检查程序状态。

若选择了“逐语句”或“逐过程”,应用程序会启动并执行,然后在第一行中断。如果选择“运行到光标处”,则应用程序启动并一直运行到断点或光标位置,具体看是断点在前还是光标在前。 可以在源窗口中设置光标位置。 某些情况下,不出现中断。 这意味着执行始终未到达设置光标处的代码。

解决方案可能包含不止一个项目。 这时候,可以选择将由“调试”菜单执行命令启动的启动项目。 或者,也可以从“解决方案资源管理器”启动选定的项目。可以使用“调试”菜单上的“开始执行(不调试)”命令,在不使用调试器的情况下开始执行项目。

 

 

中断执行

当用 Visual Studio 调试器调试应用程序时,应用程序或者正在运行(执行)或处于中断模式。 大多数调试器功能(比如在**“监视”**窗口中计算表达式)只在中断模式下可用。当执行到达一个断点或发生异常,调试器将中断程序的执行。 您可以随时手动中断执行。 如果在执行没有相应源的代码时中断,将能够在“反汇编”窗口中进行调试。

手动中断程序执行

  • 在“调试”菜单上,单击“全部中断”。

    调试器将停止所有在调试器下运行的程序的执行。 程序并不退出,可以随时恢复执行。 调试器和应用程序现在处于中断模式。

如果正在调试多个程序,则默认情况下,断点或“全部中断”命令将影响所有被调试的程序。 如果想仅中断当前程序,可以更改该默认值。

更改调试多个程序时的中断行为

  1. 在“工具”菜单上,单击“选项”。

  2. 在“选项”对话框中,选择“调试”文件夹,并单击“常规”类别。

  3. 切换“一个进程中断时则中断所有进程”。

  4. 单击“确定”。

 

 

停止调试或停止执行

停止调试意味着终止调试会话。 停止执行意味着终止正调试的进程并结束调试会话。 请勿与中断执行混淆,后者意味着暂停正在调试的进程的执行但调试会话仍处于活动状态。

停止调试

  • 在“调试”菜单上,选择“停止调试”。

如果程序是从 Visual Studio 启动的,则**“停止调试”终止正调试的进程。 如果程序附加到进程,而不是从 Visual Studio 启动的,则该进程仍继续运行。 如果要终止被附加的进程,可以通过“进程窗口”终止单个进程,或者通过“全部终止”**命令终止所有被附加的进程。

终止所有正调试的被附加进程

  • 在“调试”菜单上选择“全部终止”。

如果要停止当前正在调试的运行并立刻开始新运行,可以使用**“重新启动”**命令。

停止调试并重新启动

  • 在“调试”菜单上选择“重新启动”。

“重新启动”**停止当前正在调试的会话,并重启启动项目。

如果退出正在调试的应用程序,调试将自动停止。 如果正在调试多个程序,调试将继续进行,直到退出了最后一个程序。 如果调试的是由其他应用程序承载的项目(如由 Microsoft Internet Explorer 承载的 Web 项目),若退出宿主应用程序(如 Microsoft Internet Explorer),调试将停止。

在 Visual Basic 和 C# 中,如果正在调试一个 Web 服务,而使用该服务的客户端应用程序被终止了,则 Web 服务的调试也会停止。

单步执行

“单步执行”是最常见的调试过程之一。 “单步执行”即一次执行一行代码。

“调试”菜单提供了三个逐句通过代码的命令:

  • 逐语句

  • 逐过程

  • 跳出

“逐语句”和“逐过程”的差异仅在于它们处理函数调用的方式不同。 这两个命令都指示调试器执行下一行的代码。 如果某一行包含函数调用,“逐语句”仅执行调用本身,然后在函数内的第一个代码行处停止。 而“逐过程”执行整个函数,然后在函数外的第一行处停止。 如果要查看函数调用的内容,请使用“逐语句”。 若要避免单步执行函数,请使用“逐过程”。

在嵌套函数调用上,“逐语句”将进入并单步执行嵌套最深的函数。 如果对类似 Func1(Func2()) 的调用使用“逐语句”,调试器将进入并单步执行函数 Func2。如果要进入并单步执行特定的嵌套函数,请使用快捷菜单中的“单步执行特定函数”命令。 位于函数调用的内部并想返回到调用函数时,请使用“跳出”**。 “跳出”将一直执行代码,直到函数返回,然后在调用函数中的返回点处中断。

运行到指定位置

有时,在调试过程中,您想执行到代码中的某一点,然后中断。 如果在要中断的位置设置了断点,则可以实现上述目的。

运行到已设置断点的指定位置

  • 在“调试”菜单上,单击“启动”或“继续”。

    您其实不需要在任何情况下都设置断点。 Visual Studio 调试器提供特定命令以运行到光标位置或运行到指定的函数。

设置下一语句

在 Visual Studio 调试器中,可以移动执行点来设置要执行的下一条代码语句。 源窗口或“反汇编”窗口的空白区域中的黄色箭头标记要执行的下一条语句的位置。 通过移动此箭头,可以跳过部分代码或返回到以前执行过的行。 在某些情况下可以使用此方法,例如,跳过包含已知 bug 的代码段。注意:设置下一条语句将导致程序计数器直接跳到新位置。 使用此命令时要小心以下情况:

  • 不执行旧执行点和新执行点之间的指令。

  • 如果向后移动执行点,则不撤消插入的指令。

  • 将下一条语句移动到另一个函数或范围通常会导致调用堆栈损坏,导致一个运行时错误或异常。 如果尝试将下一条语句移动到另一个范围,则调试器将打开一个含有警告的对话框,并提供一个取消该操作的机会。 在 Visual Basic 中,不能将下一条语句移动到另一个范围或函数。

  • 在本机 C++ 中,如果已启用运行时检查,则设置下一条语句会导致执行到达方法的结尾时引发异常。

  • 当启用“编辑并继续”时,如果您做出了“编辑并继续”无法立即重新映射的编辑,则“设置下一语句”将失败。 例如,如果您编辑了 catch 块中的代码,将发生这种情况。 发生这种情况时,您将看到类似如下的错误消息:“无法将下一语句设置到此位置。不支持操作。未知错误: 错误号”

在托管代码中,在以下情况下不能移动下一条语句:

  • 下一条语句与当前语句不在同一个方法中。

  • 使用实时调试启动调试。

  • 正在展开一个调用堆栈。

  • 已引发一个 System.StackOverflowException 或 System.Threading.ThreadAbortException 异常。

应用程序处于活动运行状态时不能设置下一条语句。 要设置下一语句,调试器必须处于中断模式。

设置要执行的下一语句

  • 在源窗口中,单击黄色箭头,要将下一条语句设置到哪个位置,就将箭头拖到该位置,该位置应在同一源文件中

    - 或 -

  • 在源窗口中,右击要执行的下一条语句,然后选择“设置下一语句”。

  • 在“反汇编”窗口中,右击要执行的下一条汇编语言指令,然后选择“设置下一语句”。

使用线程和进程是调试的重要组成部分。 Visual Studio 提供一个界面,在此界面中,可连接正在运行的待调试进程,可查看在那些进程中运行的附加进程和线程的有关信息,还可以控制正在调试的线程和进程的执行。

在计算机科学中,“线程”和“进程”是两个相关的概念。 二者都表示必须按特定顺序执行的指令序列。 但是不同线程或进程中的指令可以并行执行。

进程存在于操作系统内,并对应于用户可看作为程序或应用程序的事物。 另一方面,线程存在于进程内。 因此,线程有时也称作“轻量进程”。 每个进程都由一个或多个线程组成。

多个进程的存在使得计算机能够一次执行多个任务。 而多个线程的存在使得进程能够分解工作以便并行执行。 在多处理器计算机上,进程或线程可以在不同的处理器中运行。 这使得真正的并行处理成为可能。

并不总是能够完全并行处理。 有时候必须要同步线程。 一个线程可能必须等待另一个线程的结果,或者一个线程可能需要独占访问另一个线程正在使用的资源。 同步问题是多线程应用程序中出现 Bug 的一个常见原因。 有时候线程可能最终等待的是永远不会变得可用的资源。 这导致了一种称为“死锁”的状况。

Visual Studio 调试器为调试线程和进程提供了功能强大但易于使用的工具。

线程和进程

在 Visual Studio 中用于处理进程的主要工具有“附加到进程”对话框、“进程”窗口和“调试位置”工具栏。 用于调试线程的主要工具有“线程”窗口、源窗口中的线程标记和“调试位置”工具栏。调试多线程应用程序的主要工具是“并行堆栈”和“并行任务”窗口。

下面的表显示了可用信息以及可在以上每个位置执行的操作:

用户界面

可用信息

可以执行的操作

“附加到进程”对话框

可以附加的可用进程:


  • 进程名 (.exe)

  • 进程 ID 号

  • 菜单栏标题

  • 类型(托管 v4.0;托管 v2.0、v1.1、v1.0;x86;x64;IA64)

  • 用户名(帐户名)

  • 会话号

选择要附加的进程

选择远程计算机

更改用于连接远程计算机的传输类型

“进程”窗口

附加的进程:


  • 进程名

  • 进程 ID 号

  • 进程 .exe 的路径

  • 菜单栏标题

  • 状态(中断 运行)

  • 调试(本机、托管等。)

  • 传输类型(默认、无身份验证时仅限本机)

  • 传输限定符(远程计算机)

工具:


  • 附加

  • 分离

  • 终止


快捷菜单:


  • 附加

  • 分离

  • 调试停止时分离

  • 终止

“线程”窗口

当前进程中的线程:


  • 线程 ID

  • 托管 ID

  • 类别(主线程、接口线程、远程过程调用处理程序或辅助线程)

  • 线程名

  • 创建线程的位置

  • 优先级

  • 关联掩码

  • 挂起项计数

  • 进程名

  • 标志指示器

  • 挂起指示器

工具:


  • 搜索

  • 搜索调用堆栈

  • 标记“仅我的代码”

  • 标记自定义模块选择

  • 分组依据

  • Columns

  • 展开/折叠调用堆栈

  • 展开/折叠组

  • 冻结/解冻线程


快捷菜单:


  • 在源中显示线程

  • 切换到线程

  • 冻结一个正在运行的线程

  • 解冻冻结的线程

  • 标记一个线程以便进一步研究

  • 取消标记一个线程

  • 重命名一个线程

  • 显示和隐藏线程


其他操作:


  • 查看数据提示中一个线程的调用堆栈

源窗口

左侧滚动条槽中的线程指示符指示单线程或多线程(默认情况下处于关闭状态,可通过使用“线程”窗口中的快捷菜单打开)

快捷菜单:


  • 切换到线程

  • 标记一个线程以便进一步研究

  • 取消标记一个线程

“调试位置”工具栏

  • 当前进程

  • 当前线程

  • 当前堆栈帧

  • 切换到另一个进程

  • 切换到当前进程中的另一个线程

  • 切换到当前线程中的另一个堆栈帧

  • 标记或取消标记当前线程

  • 仅显示标记的线程

“并行堆栈”窗口

  • 一个窗口中多个线程的调用堆栈。

  • 每个线程的活动堆栈帧。

  • 任何方法的调用方和被调用方。

  • 筛选出指定的线程

  • 切换到“并行任务”视图

  • 标记或取消标记线程

  • 缩放

“并行任务”窗口

  • 查看有关 Task 对象的信息,包括任务 ID、任务状态(已计划、正在运行、正在等待和已死锁)以及分配给任务的线程。

  • 调用堆栈中的当前位置。

  • 在创建时传递给任务的委托

  • 切换到当前任务

  • 标记或取消标记任务

  • 冻结或解冻任务

在运行于 Visual Studio 之外的应用程序中发生异常或崩溃时,实时调试会自动启用 Visual Studio。 这样,您便可以在 Visual Studio 没有运行时测试应用程序,并在出现问题时利用 Visual Studio 开始调试。

实时调试不适用于在可视化工具等本机应用程序中承载的托管代码。 如果您在 Windows Server 2003 或 Windows 2000 SP3(或更高版本)中安装 .NET Framework,那么,只有在计算机重新启动后,才可以对在终端服务会话中通过受限用户帐户运行的进程使用实时调试。

使用实时调试

默认情况下,安装 Visual Studio 时会启用实时调试。启用实时调试之后,您可以在 Visual Studio 之外调试应用程序。 如果发生崩溃或异常,将会出现一个对话框,其中显示一条与下面类似的消息:在 terrarium.exe[3384] 中发生未经处理的异常(“System.TypeInitializationException”)

如果出现此对话框,您可以通过以下步骤开始调试。

发生错误时开始实时调试

  1. 在“实时调试”对话框中,在“可能的调试器”列表中,单击“Visual Studio  新实例”或单击已在运行的 Visual Studio 2010。

  2. 若要在以后发生崩溃时都自动使用 Visual Studio,请单击“将当前选定的调试器设置为默认调试器”。

  3. 如果要选择能够调试的代码类型,请单击“手动选择调试引擎”。 如果没有选择此选项,Visual Studio 将根据程序中的代码类型自动选择合适的调试引擎。

  4. 单击“确定”。

  5. 如果在您的应用程序中,某个程序集包含不受信任的代码,则会出现一个对话框以及一条安全警告。 此对话框使可以决定是否继续调试。 在继续调试之前,请决定您是否信任相应代码。 代码是您自己编写的吗? 您是否信任代码编写者? 如果该应用程序正在远程计算机上运行,您是否认识进程的名称? 即便该应用程序在本地运行,也不一定表示它是可信的应用程序。 例如,在 Internet Explorer 中可能会有恶意 ActiveX 控件运行。 请考虑此类恶意代码在您的计算机中运行的可能性。 如果您确信待调试代码值得信任,请单击“调试”。 否则,请单击“不调试”。

启用或禁用实时调试

您可以在“选项”对话框中启用或禁用实时调试。

启用或禁用实时调试

  1. 在“工具”菜单上,单击“选项”。

  2. 在“选项”对话框中选择“调试”文件夹。

  3. 在“调试”文件夹中选择“实时”页。

  4. 在“启用这些代码类型的实时调试”框中,选中或清除相关的程序类型:“托管”、“本机”或“脚本”。

    要在启用实时调试后禁用它,必须使用管理员特权运行。 启用实时调试会设置一个注册表项,需要管理员特权才可以更改该项。

  5. 单击“确定”。

默认情况下,Windows 窗体应用程序有一个顶级的异常处理程序,该处理程序允许程序在能够恢复时继续运行。 因此,若要启用 Windows 窗体应用程序的实时调试,还必须执行下列步骤。

为 Windows 窗体启用实时调试

  1. 在 machine.config 或应用程序.exe.config 文件的 system.windows.form 节中,将 jitDebugging 值设置为 true。

  • <configuration>
        <system.windows.forms jitDebugging="true" />
    </configuration>
    
  • 在 C++ Windows 窗体应用程序中,还必须在 .config 文件或您的代码中设置 DebuggableAttribute。 如果在编译时使用 /Zi 而没有使用 /Og,则编译器会替您设置此特性。 然而,如果您想要调试非优化发布版本,则必须自行设置此项。 为此,您可以在应用程序的 AssemblyInfo.cpp 文件中添加下面一行:

  1. [assembly:System::Diagnostics::DebuggableAttribute(true, true)]; 

即便在您的计算机中不再安装有 Visual Studio,仍可启用实时调试。 如果没有安装 Visual Studio,则不能在 Visual Studio“选项”对话框中禁用实时调试。 对于这种情况,您可以通过编辑 Windows 注册表来禁用实时调试。

通过编辑注册表禁用实时调试

  1. 在“开始”菜单中,单击“运行”。

  2. 在“运行”对话框中,键入 regedit,然后单击“确定”。

  3. 在“注册表编辑器”窗口中,找到并删除下列注册表项:


    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger

    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\DbgManagedDebugger

  4. 如果您的计算机运行的是 64 位操作系统,还请删除下列注册表项:


    • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger

    • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\DbgManagedDebugger

  5. 注意不要意外删除或更改任何其他注册表项。

  6. 关闭“注册表编辑器”窗口。

实时调试错误

您可能会遇到与实时调试相关联的下列错误消息。

  • <程序> 中发生未处理的 win32 异常。对此异常的实时调试失败,错误为: 登录用户没有调试崩溃应用程序的权限。

    此信息指出:由于您没有正确的访问权限,实时调试失败。

  • 无法附加到崩溃进程。 指定的程序不是 Windows 或 MS-DOS 程序。

    当您尝试附加到 Windows 2000 下作为另一个用户运行的进程时会发生该错误。

    若要解决此问题,请启动 Visual Studio,从“调试”菜单打开“附加到进程”对话框,然后在“可用进程”列表中找到您要调试的进程。 如果您不知道进程名称,请查看“Visual Studio 实时调试器”对话框并记下进程 ID。 在“可用进程”列表中选择该进程并单击“附加”。 在“Visual Studio 实时调试器”对话框中单击“否”以关闭该对话框。

  • 未能启动调试器,因为没有用户登录。

    在没有用户登录到控制台的计算机中,如果实时调试尝试启动 Visual Studio,则会发生此错误。 因为没有用户登录,所以没有用户会话来显示“实时调试”对话框。

    要解决此问题,请登录到计算机。

  • 类没有注册。

    此错误指出:调试器尝试创建一个可能是因为安装问题而没有注册的 COM 类。

    若要解决此问题,请使用安装盘重新安装或修复 Visual Studio 安装。

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

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

  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