用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. hdu 4965 Fast Matrix Calculation

    题目链接:hdu 4965,题目大意:给你一个 n*k 的矩阵 A 和一个 k*n 的矩阵 B,定义矩阵 C= A*B,然后矩阵 M= C^(n*n),矩阵中一切元素皆 mod 6,最后求出 M 中所 ...

  2. jquery实现全选、反选、不选

    <!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8&quo ...

  3. jQuery中$.post()的使用

    $.post()方法是jquery本身对ajax的一个简单封装,其效果等价于: $.ajax({ url:url, type:"POST", data:data, dataType ...

  4. Spring MVC 之拦截器(八)

     在springMVC中实现拦截器有两种方式 1.实现HandlerInterceptor接口 2.继承HandlerInterceptorAdaptor类 编写拦截器: package com.cy ...

  5. Spring MVC 入门基础(一)

    一.Spring Web MVC是什么? Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解 ...

  6. Apache mod_jk

    http://tomcat.apache.org/connectors-doc/generic_howto/loadbalancers.html http://tomcat.apache.org/co ...

  7. 【转】java多态详解

    1.        Java中除了static和final方法外,其他所有的方法都是运行时绑定的.private方法都被隐式指定为final的,因此final的方法不会在运行时绑定.当在派生类中重写基 ...

  8. iOS 细碎知识整理

    1centerX,即x轴的中点 centery,即y轴的中点

  9. ObjectMapper处理从远程获取的Object对象

    微服务中从其他服务获取过来的对象,如果从Object强转为自定义的类型会报错,利用ObjectMapper转换. ObjectMapper mapper = new ObjectMapper(); D ...

  10. [转]Android各大网络请求库的比较及实战

    自己学习android也有一段时间了,在实际开发中,频繁的接触网络请求,而网络请求的方式很多,最常见的那么几个也就那么几个.本篇文章对常见的网络请求库进行一个总结. HttpUrlConnection ...