用windbg调试C#代码是比较麻烦的,因为windbg是针对OS层级的,而C#被CLR隔了一层,很多原生的命令如查看局部变量dv、查看变量类型dt等在CLR的环境中都不能用了。必须使用针对CLR的扩展命令,比如sos、psscor2中的命令。下面以一个最简单的WPF程序来说明调试的典型步骤,以及典型的坑。

1、用正确版本的windbg、加载正确版本的扩展模块

  1. 把程序跑起来,看任务管理器中是32位 or 64位进程,32-bit用windbg x86、64-bit用windbg x64调试。

  2. 如果是.dump文件,恐怕就要在获取的时候,查看对应进程的信息了。

  3. 判断是.net2.0 or .net4.0的程序:lmvm clr,如果有详细信息,表示是net40的程序。如果为none,则lmvm mscorwks,显示详情则表示是net20的程序。

  4. 根据net20 or net40用.loadby sos clr或.loadby sos mscorwks加载对应的sos版本。当然也可以使用.load [moduleName]直接加载,但要确保版本正确。

  5. 可以用.chain查看已加载的extension,如果没有sos之类的,那么这个扩展下的命令都不可用,比如!DumpDomain 会报“No export NoExist found”。

  6. 不同的扩展可能存在相同的命令,比如sos和psscor2里大部分命令都是同名的,可能参数列表不同。可以用![extension].[command]的方式区分,比如!sos.DumpDomain和!psscor2.DumpDomain。如果不加extensionName,那么会默认使用.chain列表出来的第一个扩展的命令。

  7. 如果加载不成功,可以.cordll -ve -u -l看到出错的详细信息,一般都是版本没有正确匹配。一般都建议:不论是32位还是64位的进程,都抓32位的dump;具体操作中,由于TaskMgr和ProcExp都存在32位+64位的版本,因此强烈建议只用ProcDump -ma [ProcessName]抓Dump,然后根据Process的32 or 64位,选用Windbg的x86 or x64位。比如,我一个64位的进程,抓了一个64位的dump,.loadby sos clr时报如下错:

0:000> .loadby sos clr
The call to LoadLibrary(C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos) failed, Win32 error 0n193
“%1 is not a valid Win32 application.”
Please check your debugger configuration and/or network access.

2、如何查看元数据,如何在感兴趣的地方下断点

2.1、如果不是自己写的代码,可以用如下命令:
!DumpDomain
Module Name
00252eac D:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\bin\Debug\TestWindbg_LocalVariables.exe !DumpModule -mt [moduleName, such as: 00252eac]
MT TypeDef Name
------------------------------------------------------------------------------
00258b6c 0x02000002 TestWindbg_LocalVariables.MainWindow
002572b4 0x02000003 TestWindbg_LocalVariables.App !DumpMT -md 00258b6c
Entry MethodDe JIT Name
003e02e8 00258afc JIT TestWindbg_LocalVariables.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs) !bpmd -md 00258afc
MethodDesc = 00258afc
Setting breakpoint: bp 003E02E8 [TestWindbg_LocalVariables.MainWindow.Button_Click(System.Object, System.Windows.RoutedEventArgs)]
2.2、如果是自己写的代码,那就方便了,直接:
!bpmd TestWindbg_LocalVariables MainWindow.Button_Click

3、如何查看和修改局部变量

Button_Click里的源码如下:

private void Button_Click(object sender, RoutedEventArgs e){
int a = 1;
int b = 22;
int c = a + b;
MessageBox.Show(c.ToString());
} !clrstack -i //能很方便的提供对命令的链接
Child SP IP Call Site
003ce5e0 003e0326 [DEFAULT] [hasThis] Void TestWindbg_LocalVariables.MainWindow.Button_Click(Object,Class System.Windows.RoutedEventArgs) (D:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\bin\Debug\TestWindbg_LocalVariables.) !ClrStack -i -a 0
PARAMETERS:
+ TestWindbg_LocalVariables.MainWindow this @ 0x268652c
+ System.Windows.Controls.Button sender @ 0x269b1d4
+ System.Windows.RoutedEventArgs e @ 0x2756720
LOCALS:
+ int a = 1
+ int b = 22
+ int c = 0 !U /d 003e0326
d:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\MainWindow.xaml.cs @ 30:
003e0318 c745f401000000 mov dword ptr [ebp-0Ch],1 d:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\MainWindow.xaml.cs @ 31:
003e031f c745f016000000 mov dword ptr [ebp-10h],16h d:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\MainWindow.xaml.cs @ 32:
>>> 003e0326 8b45f4 mov eax,dword ptr [ebp-0Ch]
003e0329 0345f0 add eax,dword ptr [ebp-10h]
003e032c 8945ec mov dword ptr [ebp-14h],eax // F10到这一步,寄存器eax里add的结果,即将被存到c里,修改eax即可 d:\project\TestWindbg_LocalVariables\TestWindbg_LocalVariables\MainWindow.xaml.cs @ 33:
003e032f 8d4dec lea ecx,[ebp-14h]
003e0332 e8e9001355 call mscorlib_ni+0x2e0420 (55510420) (System.Int32.ToString(), mdToken: 06000d5f)
003e0337 8945e4 mov dword ptr [ebp-1Ch],eax
003e033a 8b4de4 mov ecx,dword ptr [ebp-1Ch]
003e033d e862a04005 call PresentationFramework_ni+0x9fa3a4 (057ea3a4) (System.Windows.MessageBox.Show(System.String), mdToken: 06006934)
003e0342 8945e8 mov dword ptr [ebp-18h],eax

可以看出汇编与源码间的对应关系,比如我们想修改c = 25,可以F10到“mov dword ptr [ebp-14h],eax”这一步,如下:

eax=00000017 // 0x17=23
r eax=19
r eax //验证一下是否已修改
eax=00000019
g !DumpHeap -type System.Windows.Controls.Button
MT Count TotalSize Class Name
051bc3bc 1 248 System.Windows.Controls.Button !dso
OS Thread Id: 0x310c (0)
ESP/REG Object Name
ebx 0269b1d4 System.Windows.Controls.Button !do -nofields 0269b1d4
Name: System.Windows.Controls.Button
MethodTable: 051bc3bc
EEClass: 04e39738
Size: 248(0xf8) bytes
File: C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll

run下去,可以看到MessageBox.Show出来的是25。另外也可以配合!DumpHeap、!DumpStackObjects(dso)、!DumpObj(do)等命令查找感兴趣的对象。最后,多看帮助,windbg的帮助非常详实。多看extension自带的帮助:!sos.help、!help DumpDomain等。

4、如何分析高内存(待续)

5、如何分析高CPU(待续)

6、引用

windbg调试C#代码(一)的更多相关文章

  1. windbg调试C#代码(二)

    这篇主要讲如何分析高内存和高CPU. 1.如何分析高内存 注:如果抓Dump的同时,刚好在执行GC,抓出来的Dump执行命令多半会出错,用!VerifyHeap也能验证Dump有误,这种情况只能重新抓 ...

  2. 调试SQLSERVER (三)使用Windbg调试SQLSERVER的一些命令

    调试SQLSERVER (三)使用Windbg调试SQLSERVER的一些命令 调试SQLSERVER (一)生成dump文件的方法调试SQLSERVER (二)使用Windbg调试SQLSERVER ...

  3. 调试SQLSERVER (二)使用Windbg调试SQLSERVER的环境设置

    调试SQLSERVER (二)使用Windbg调试SQLSERVER的环境设置 调试SQLSERVER (一)生成dump文件的方法调试SQLSERVER (三)使用Windbg调试SQLSERVER ...

  4. 开源项目asmjit——调用自定义方法demo以及windbg调试

    asmjit是一个开源项目,使用它可以将代码即时的编译成机器码,也就是所谓的jit技术. 初次接触这个项目,编写了一个demo,学习它的使用方法. 现将编写的demo以及调试jit生成的机器码的过程总 ...

  5. 使用WinDbg调试SQL Server查询

    上一篇文章我给你介绍了WinDbg的入门,还有你如何能附加到SQL Server.今天的文章,我们继续往前一步,我会向你展示使用WinDbg调试SQL Server查询需要的步骤.听起来很有意思?我们 ...

  6. WinDbg调试流程的学习及对TP反调试的探索

    基础知识推荐阅读<软件调试>的第十八章 内核调试引擎 我在里直接总结一下内核调试引擎的几个关键标志位,也是TP进行反调试检测的关键位. KdPitchDebugger : Boolean ...

  7. WinDbg 调试.net程序

    WinDbg支持以下三种类型的命令: ·        常规命令,用来调试进程 ·        点命令,用来控制调试器 ·        扩展命令,可以添加叫WinDbg的自定义命令,一般由扩展dl ...

  8. WinDBG调试.NET程序示例

    WinDBG调试.NET程序示例 好不容易把环境打好了,一定要试试牛刀.我创建了一个极其简单的程序(如下).让我们期待会有好的结果吧,阿门! using System; using System.Co ...

  9. 内核,配置WinDbg,调试操作系统(双机调试)

    配置WinDbg,调试操作系统(双机调试) PS: 设置双机调试之前,请先安装虚拟机,并且安装好XP系统.这里不做演示.直接设置. 一丶WinDbg的设置 1) 配置WinDbg的环境,在path变量 ...

随机推荐

  1. Java中的数学运算BigDecimal

    Math类 package ch7; /** * Created by Jiqing on 2016/11/24. */ public class MathDemo { public static v ...

  2. 算法_栈的Java的通用数组实现

    栈是一个常用的最简单的数据结构,这里提供了其实现.内部维护了一个数组,并且可以动态的调整数组的大小.而且,提供了迭代器支持后进先出的迭代功能.Stack的实现是所有集合类抽象数据类型实现的模板,它将所 ...

  3. 在代码中修改TextView的DrawableRight图片

    TextView的xml <TextView android:id="@+id/textciew1" android:layout_width="match_par ...

  4. SDL2.0的加载图片贴图

    加载图片贴图,采用了SDL_Window.SDL_Renderer.SDL_Texture和SDL_Image库 实例: #include <stdio.h> #include <m ...

  5. android中textview设置为多行文本时,如何让文字从最顶开始显示

    <span style="white-space:pre"> </span><EditText android:layout_width=" ...

  6. Linux技巧学习

    主要是收集一些Linux的技巧: 1.编写可靠shell脚本的八个建议 指定bash,推荐使用 /usr/bin/env bash 和 /bin/bash,不要使用/usr/bin/bash. set ...

  7. 项目框架开发流程(oa项目为例)

    1. 导包 2. 配置web.xml 3. 设计通用dao ,base,service, action, domain  ,utils等 4.配置struts.xml 和 beans.xml 5. 配 ...

  8. java 集合4(迭代器)

    迭代器使用要注意的问题: 1.迭代器在遍历元素的时候注意事项: 在迭代器迭代元素的过程中,不准使用集合对象改变集合中的元素个数, 如果要添加或删除要用迭代器的方法. 2.如果使用类集合对象改变集合中的 ...

  9. js二级导航

    js写二级导航要点 1.ul li 2.js获取元素 3.setInterval(function(),time); 代码如下 <style type="text/css"& ...

  10. OpenGL 简介

    OpenGL是一个底层图形库规范.它为程序员提供了一个小的几何图元(点.线.多边形.图片和位图)库和一个支持2D/3D几何对象绘图命令库,通过所提供的图元和命令来控制对象的呈现(绘图). 由于Open ...