用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. Android 面试题总结

    Android 面试题总结(不断更新) 1.INETNT几种有关Activit的启动方式FLAG_ACTIVITY_BROUGHT_TO_FRONT 将ACTIVITY带到最前面FLAG_ACTIVI ...

  2. D3.js 选择元素和绑定数据/使用数据

    选择元素和绑定数据是 D3 最基础的内容,本文将对其进行一个简单的介绍. 一.如何选择元素 在 D3 中,用于选择元素的函数有两个: d3.select():是选择所有指定元素的第一个 d3.sele ...

  3. CSocket必须使用stream socket不能够使用数据报 socket

    如果使用MFC socket类CSoket通讯,必须使用stream socket,不能够使用 SOCK_DGRAM 类型socket.原因如下: 1 stream socket和数据报socket的 ...

  4. git服务器搭建-new

    http://blog.chinaunix.net/uid-26729093-id-4652536.html 基本命令使用:http://www.cnblogs.com/xdao/p/linux_gi ...

  5. Machine Learning – 第2周(Linear Regression with Multiple Variables、Octave/Matlab Tutorial)

    Machine Learning – Coursera Octave for Microsoft Windows GNU Octave官网 GNU Octave帮助文档 (有900页的pdf版本) O ...

  6. windows 下使用 Filezilla server 搭建 ftp 服务器

    windows 下使用 Filezilla server 搭建 ftp 服务器 1. Filezilla server 免费,开源, ftp 服务端 2. 下载安装, windows  https:/ ...

  7. ARPG客户端中场景对象体系设计

    一.场景对象体系 二.场景对象生命周期管理 场景对象的生命周期,不适合采用原始的c++管理方式, 即由使用者自己负责删除.而应该采用引用计数方式, 自动负责删除. 采用引用计数方式, 目前用法比较广的 ...

  8. struts2文件下载相关信息

    struts.xml文件配置: <span style="font-size:16px;"><?xml version="1.0" encod ...

  9. centos svn服务器安装

    1.安装必须的软件 yum install httpd httpd-devel subversion mod_dav_svn mod_auth_mysql 2.创建代码库 mkdir -p /root ...

  10. ubuntu安装SCrapy

    依次安装 sudo apt-get install build-essential; sudo apt-get install python-dev; sudo apt-get install lib ...