用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. maven入门

    1.1.项目构建 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服务于基于Java平台的项目构建,依赖管理和项目信息管理. 项目构建过程包括 ...

  2. Android广播BroadcastReceiver 二

    BroadcastReceiver: 在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制.而BroadcastReceiver是对发送出来的 Broadcast进行过滤 ...

  3. hdu 4414 Finding crosses

    题目链接:hdu 4414 其实是一道简单的字符型水题,不涉及任何算法,可比赛时却没能做出来,这几天的状态都差到家了... 题目大意是求有多少个满足条件的十字架,十字架的边不能有分叉路口,所以枚举每个 ...

  4. form属性method="get/post

    form属性method="get/post"的两种方式对比 在B/S应用程序中,前台与后台的数据交互,都是通过HTML中Form表单完成的.Form提供了两种数据传输的方式——g ...

  5. Spring多数据源的配置和使用

    1. 配置多个数据源 最近开发一个数据同步的小功能,需要从A主机的Oracle数据库中把数据同步到B主机的Oracle库中.当然能够用dmp脚本或者SQL脚本是最好,但是对于两边异构的表结构来说,直接 ...

  6. LinuxShell脚本攻略--第一章 小试牛刀

    使用 shell 进行数学运算: #!/bin/bash no1=; no2=; let result=no1+no2 echo $result result=$[ $no1 + no2 ] resu ...

  7. 如何进行shell脚本正确性测试

    在实际工作中,需要对shell脚本进行正确性测试. 如何用最快最有效的方式进行测试? 很多开发的习惯是,二话不说,写完/拿到,就跑一把,看看输入,输出,想要的操作是否完成,也就过了. 其实这是十分不严 ...

  8. jQuery Ajax学习

    地址:http://www.w3school.com.cn/jquery/jquery_ref_ajax.asp

  9. HTML5自学笔记[ 9 ]HTML5实现元素的拖放

    要想在html5中实现元素的拖放,被拖放元素就必须设置属性draggable="true";被拖放元素被放置的地方是另外一个元素,该元素是目标元素:这两个元素在拖放过程中都会触发不 ...

  10. ubuntu安装bower失败的解决方法

    1.安装nodejs 2.安装npm 3.安装bower 最开始使用 npm install bower -g / sudo npm install bower -g 安装bower后 命令行输入bo ...