windbg

阅读 / 问答 / 标签

Windbg如何设置应用程序的断点

,设置为 cache*d:symbols;srv*http://msdl.microsoft.com/download/symbols 可以将路径更改为自己本地的缓存路径。如果有一把好梯子的话,设置为全局代理模式,在调试的时候,会将.NET的框架PDB文件下载到该缓存目录里,我们在调试的时候就能看到更详细的信息。 当然,也可以通过命令行来主动获取微软官方调试符号。symchk /r C:WindowsSystem32*.dll /s SRV*D:symbols*http://msdl.microsoft.com/download/symbolssymchk C:WINDOWSSystem32KERNELBASE.dll /s SRV*D:symbols*http://msdl.microsoft.com/download/symbols2、加载正确版本CLR以及SOS(Son of Strike)。Windbg用户模式下,调试.Net 应用程序,我们需要正确的加载CLR以及SOS(Son of Strike)。需要注意的是,加载的CLR以及SOS版本一定要正确。如果应用程序在X86平台下编译,则需要加载C:WindowsMicrosoft.NETFrameworkv4.0.30319 目录下的SOS以及CLR,64位下编译的话,需要加载C:WindowsMicrosoft.NETFramework64v4.0.30319目录下的SOS以及CLR。2.0的程序需要加载MSCORWKS。3、例子以一个简单的Demo为例,来看一下如何在Windbg中设置断点。(在4.0FrameWork、X86平台下编译)。这个程序,根据体重身高来计算BMI指数,假定BMI指数为21的为最健康的,对给定的人员列表按照偏差大小的绝对值进行排序。让我们姑且认为偏差越小身体越健康吧。 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace WindbugDemo 7 { 8 public class Person 9 {10 //认为BMI和21偏差最小的为最健康的11 private const double BmiHelthConst = 21f;12 13 public string Name { get; set; }14 public int Age { get; set; }15 public double Height { get; set; }16 public double Weight { get; set; }17 public double BmiVariance { get { return GetBmiVariance(); } }18 //18岁至65岁可以Weight/(Height*Height)计算,否则抛出异常19 public double GetBmiVariance()20 {21 if (Age > 65 || Age < 18)22 throw new Exception("18岁以下65岁以上人群不适用此计算方法");23 double bmi = Math.Round(Weight / Math.Pow(Height, 2),2);24 double variance = Math.Abs(bmi - BmiHelthConst);25 return variance;26 }27 }28 29 public class HelthCompare : IComparer<Person>30 {31 public int Compare(Person x, Person y)32 {33 34 double diffx = x.BmiVariance;35 double diffy = y.BmiVariance;36 if (diffx == diffy)37 return 0;38 if (diffx > diffy)39 return 1;40 return -1;41 }42 }43 44 class Health45 {46 [STAThread]47 static void Main(string[] args)48 {49 Person person1 = new Person { Name = "James", Age = 35, Height = 1.70, Weight = 70 };50 Person person2 = new Person { Name = "Tony", Age = 25, Height = 1.65, Weight = 60 };51 Person person3 = new Person { Name = "John", Age = 30, Height = 1.75, Weight = 90 };52 Person[] array = new Person[] { person1, person2, person3 };53 List<Person> list = new List<Person>();54 list.AddRange(array);55 HelthCompare comparer = new HelthCompare();56 list.Sort(comparer);57 foreach(var item in list)58 {59 string text = string.Format("Name:{0} Age:{1} Height:{2} Weight:{3} BMI Variance:{4}",60 item.Name,item.Age, item.Height, item.Weight, item.BmiVariance);61 System.Console.WriteLine(text);62 }63 Console.ReadKey();64 /*65 Name:Tony Age:25 Height:1.65 Weight:60 BMI Variance:1.0466 Name:James Age:35 Height:1.7 Weight:70 BMI Variance:3.2267 Name:John Age:30 Height:1.75 Weight:90 BMI Variance:8.3968 */69 }70 }71 72 }3.1 打开Windbg,在File==》Open Executable...打开编译后的程序。指定PDB路径以及源码路径。0:000> .sympath+ d:sourceSymbol search path is: cache*d:symbols;srv*http://msdl.microsoft.com/download/symbols;d:sourceExpanded Symbol search path is: cache*d:symbols;srv*http://msdl.microsoft.com/download/symbols;d:sourceSource search path is: d:source0:000> .reloadReloading current modules.....3.2 可以使用 sxe ld:clrjit 命令,这个命令发生在clrjit加载的时候,在进入Main方法之前,这对于我们设置自己程序的断点很方便。然后输入g命令,当加载clrjit的时候,就可以命中断点了。0:000> sxe ld:clrjit0:000> g(cc8.cd0): Unknown exception - code 04242420 (first chance)ModLoad: 6d110000 6d18d000 C:WindowsMicrosoft.NETFrameworkv4.0.30319clrjit.dlleax=00000000 ebx=00000000 ecx=001437a4 edx=00000001 esi=7ffdf000 edi=0027e340eip=76df70b4 esp=0027e258 ebp=0027e2ac iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246ntdll!KiFastSystemCallRet:76df70b4 c3 ret0:000> .load C:WindowsMicrosoft.NETFrameworkv4.0.30319sos.dll0:000> .load C:WindowsMicrosoft.NETFrameworkv4.0.30319clr.dll0:000> .loadby sos clr (等同于上面两条命令)3.3 加载完SOS后,就可以用扩展命令来设置断点了。0:000> !name2ee Health!WindbugDemo.HealthModule: 00142edcAssembly: Health.exeToken: 02000004MethodTable: 001437b8EEClass: 00141304Name: WindbugDemo.Health0:000> !dumpmt -md 001437b8EEClass: 00141304Module: 00142edcName: WindbugDemo.HealthmdToken: 02000004File: D:inHealth.exeBaseSize: 0xcComponentSize: 0x0Slots in VTable: 6Number of IFaces in IFaceMap: 0--------------------------------------MethodDesc Table Entry MethodDe JIT Name6647952c 6619612c PreJIT System.Object.ToString()6648ec30 66196134 PreJIT System.Object.Equals(System.Object)6648e860 66196154 PreJIT System.Object.GetHashCode()6648e2a0 66196168 PreJIT System.Object.Finalize()0014c015 001437b0 NONE WindbugDemo.Health..ctor()0014c011 001437a4 NONE WindbugDemo.Health.Main(System.String[])0:000> !dumpmt -md 001437b8EEClass: 00141304Module: 00142edcName: WindbugDemo.HealthmdToken: 02000004File: D:inHealth.exeBaseSize: 0xcComponentSize: 0x0Slots in VTable: 6Number of IFaces in IFaceMap: 0--------------------------------------MethodDesc Table Entry MethodDe JIT Name6647952c 6619612c PreJIT System.Object.ToString()6648ec30 66196134 PreJIT System.Object.Equals(System.Object)6648e860 66196154 PreJIT System.Object.GetHashCode()6648e2a0 66196168 PreJIT System.Object.Finalize()0014c015 001437b0 NONE WindbugDemo.Health..ctor()0014c011 001437a4 NONE WindbugDemo.Health.Main(System.String[])0:000> !bpmd -md 001437a4 MethodDesc = 001437a4Adding pending breakpoints...在上面的Windbg调试窗口里,JIT为NONE的就表示还没有进行JIT编译。这种情况下,我们不能使用bp命令来设置断点的。我们可以使用bpmd命令加md参数来设置断点。输入g命令程序继续执行。0:000> !u 001437a4 Normal JIT generated codeWindbugDemo.Health.Main(System.String[])Begin 011f0050, size 5ccd:source2HealthHealth.cs @ 48:011f0050 55 push ebp011f0051 8bec mov ebp,esp... ...d:source2HealthHealth.cs @ 56:011f0377 8b8d68ffffff mov ecx,dword ptr [ebp-98h]011f037d 8b9564ffffff mov edx,dword ptr [ebp-9Ch]011f0383 3909 cmp dword ptr [ecx],ecx011f0385 e822022b65 call mscorlib_ni+0x3105ac (664a05ac) (System.Collections.Generic.List`1[[System.__Canon, mscorlib]].Sort(System.Collections.Generic.IComparer`1<System.__Canon>), mdToken: 06002283)011f038a 90 nop... ...0:000> bp 011f0377 0:000> g3.4 对于已经JIT编译的方法,我们可以采用u命令,查看反汇编,然后就可以在对应的行号用非托管应用程序的bp命令来设置断点了。以上两种方法可以在Windbg下设置断点。查找方法表还可以根据domain信息查找Module信息0:000> !dumpdomain--------------------------------------System Domain: 67840f60LowFrequencyHeap: 67841284HighFrequencyHeap: 678412ccStubHeap: 67841314Stage: OPENName: None--------------------------------------Shared Domain: 67840c08LowFrequencyHeap: 67841284HighFrequencyHeap: 678412ccStubHeap: 67841314Stage: OPENName: NoneAssembly: 003b24f0 [C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll]ClassLoader: 003b25b8 Module Name66191000 C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll--------------------------------------Domain 1: 00364d50LowFrequencyHeap: 003651a4HighFrequencyHeap: 003651ecStubHeap: 00365234Stage: OPENSecurityDescriptor: 00366920Name: Health.exeAssembly: 003b24f0 [C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll]ClassLoader: 003b25b8SecurityDescriptor: 003af690 Module Name66191000 C:WindowsMicrosoft.NetassemblyGAC_32mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dllAssembly: 003bfbd8 [D:inHealth.exe]ClassLoader: 003bfca0SecurityDescriptor: 003bf880 Module Name00142edc D:inHealth.exe0:000> !dumpmodule -mt 00142edc Name: D:inHealth.exeAttributes: PEFile Assembly: 003bfbd8LoaderHeap: 00000000TypeDefToMethodTableMap: 00140038TypeRefToMethodTableMap: 0014004cMethodDefToDescMap: 0014009cFieldDefToDescMap: 001400dcMemberRefToDescMap: 00000000FileReferencesMap: 001400f8AssemblyReferencesMap: 001400fcMetaData start address: 0123237c (2360 bytes)Types defined in this module MT TypeDef Name------------------------------------------------------------------------------001437b8 0x02000004 WindbugDemo.HealthTypes referenced in this module MT TypeRef Name------------------------------------------------------------------------------665941b8 0x02000001 System.Object0:000> !dumpmt -md 001437b8EEClass: 00141304Module: 00142edcName: WindbugDemo.HealthmdToken: 02000004File: D:inHealth.exeBaseSize: 0xcComponentSize: 0x0Slots in VTable: 6Number of IFaces in IFaceMap: 0--------------------------------------MethodDesc Table Entry MethodDe JIT Name6647952c 6619612c PreJIT System.Object.ToString()6648ec30 66196134 PreJIT System.Object.Equals(System.Object)6648e860 66196154 PreJIT System.Object.GetHashCode()6648e2a0 66196168 PreJIT System.Object.Finalize()0014c015 001437b0 NONE WindbugDemo.Health..ctor()0014c011 001437a4 NONE WindbugDemo.Health.Main(System.String[])3.5 也可以通过JIT编译的代码地址来设置断点。0:000> !name2ee Health!Win

windbg使用方法

  windbg使用方法是:   1、如果还没有安装过Windbg,首先要下载安装它。打开百度首页,搜索Windbg,点击高速下载,然后安装。   2、安装成功后,可以点击开始菜单,程序中找到并启动Windbg。   3、启动后主界面。   4、可以选择文件(File)菜单附加到一个进程。   5、在打开的列表中选择要调试的进程。   6、有的进程可能权限比较高,无法调试。   7、使用管理员身份运行Windbg。   8、再选择进程,附加进程。

如何使用Windbg分析崩溃dump

调试Dump文件很简单,双击自动打开VC然后F7运行。但是中间要注意很多事情。1。Dump文件放在哪里Dump文件不用非要放在你编译出来的位置,你完全可以建立一个新的文件夹来放它。2。要恢复当时的现场可能你要问,怎么可能,这个dump文件可是用户发给我的,我不可能去用户家里调试吧?这个恢复现场可不是指的非要到那台机器上去,而是要把产生dump文件对应的二进制文件拿到。但是恢复现场需要所有的二进制文件都要对应,你一定要有导致用户崩溃的那些Exe和Dll。既然是你发布的程序,Exe文件当然你会有。所以这里只考虑Dll就行了。Dump文件中记录了所有dll文件的版本号和时间戳,所以你一定可以同过某种途径拿到它。如果你能从用户那里拿到最好,如果不方便,用户不可能用的是我们平常不常用的操作系统,所以找个有对应系统的机器一般都会有。但是记住不光是文件名称要一致,还要核对版本和时间戳,如果不同一样没有办法用。

WinDbg怎么用?

什么是WinDBG? WinDbg是微软开发的免费源码级调试工具。Windbg可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。由于大部分程序员不需要做Kernel模式调试, 我在这篇文章中不会介绍Kernel模式调试。Kernel模式调试对学习Windows核心极有帮助。如果你对此感兴趣,可以阅读Inside Windows 2000和Windbg所带的帮助文件。这篇文章得主要目的是介绍WINDBG的主要功能以及相关的命令。关于这些命令的详细语法,请参阅帮助文件。对文章中提到的许多命令,WINDBG有相应的菜单选项。如何得到帮助在命令(Command)窗口中输入.hh 命会调出帮助文件令。.hh keyword会显示关于keyword的详细命令。启动DebuggerWindbg可以用于如下三种调试:远程调试:你可以从机器A上调试在机器B上执行的程序。具体步骤如下:? 在机器B上启动一个调试窗口(Debug Session)。你可以直接在Windbg下运行一个程序或者将Windbg附加(Attach)到一个进程。? 在机器B的Windbg命令窗口上启动一个远程调试接口(remote):.server npipe:pipe=PIPE_NAMEPIPE_NAME是该接口的名字。? 在机器A上运行:windbg –remote npipe:server=SERVER_NAME,pipe=PIPE_NAMESERVER_NAME是机器B的名字。Dump文件调试:如果在你的客户的机器上出现问题,你可能不能使用远程调试来解决问题。你可以要求你的用户将Windbg附加到出现问题的进程上,然后在命令窗口中输入:.dump /ma File Name创建一个Dump文件。在得到Dump文件后,使用如下的命令来打开它:windbg –z DUMP_FILE_NAME本地进程调试:你可以在Windbg下直接运行一个程序:Windbg “path to executable” arguments 也可以将Windbg附加到一个正在运行的程序: Windbg –p “process id” Windbg –pn “process name” 注意有一种非侵入(Noninvasive)模式可以用来检查一个进程的状态并不进程的执行。当然在这种模式下无法控制被调试程序的执行。这种模式也可以用于查看一个已经在Debugger控制下运行的进程。具体命令如下: Windbg –pv –p “process id” Windbg –pv –pn “process name” 调试多个进程和线程如果你想控制一个进程以及它的子进程的执行,在Windbg的命令行上加上-o选项。Windbg中还有一个新的命令.childdbg 可以用来控制子进程的调试。如果你同时调试几个进程,可以使用 | 命令来显示并切换到不同的进程。在同一个进程中可能有多个线程。~命令可以用来显示和切换线程。调试前的必备工作在开始调试前首先要做的工作是设置好符号(Symbols)路径。没有符号,你看到的调用堆栈基本上毫无意义。Microsoft的操作系统符号文件(PDB)是对外公开的。另外请注意在编译你自己的程序选择生成PDB文件的选项。如果设置好符号路径后,调用堆栈看起来还是不对。可以使用lm, !sym noisy, !reload 等命令来验证符号路径是否正确。Windbg也支持源码级的调试。在开始源码调试前,你需要用.srcpath设置源代码路径。如果你是在生成所执行代码的机器上进行调试,符号文件中的源码路径会指向正确的位置,所以不需要设置源代码路径。如果所执行代码是在另一台机器上生成的,你可以将所用的源码拷贝(保持原有的目录结构)的一个可以访问的文件夹(可以是网络路径)并将源代码路径设为该文件夹的路径。注意如果是远程调试,你需要使用.lsrcpath来设置源码路径。静态命令:显示调用堆栈:在连接到一个调试窗口后,首先要知道的就是程序当前的执行情况k* 命令显示当前线程的堆栈。~*kb会显示所有线程的调用堆栈。如果堆栈太长,Windbg只会显示堆栈的一部分。.kframes可以用来设置缺省显示框架数。显示局部变量:接下来要做通常是用dv显示局部变量的信息。CTRL+ALT+V可以切换到更详细的显示模式。关于dv要注意的是在优化过的代码中dv的输出极有可能是不准确的。这时后你能做的就是阅读汇编代码来发现你感兴趣的值是否存储在寄存器中或堆栈上。有时后当前的框架(Frame)上可能找不到你想知道的数据。如果该数据是作为参数传到当前的方法中的,可以读一读上一个或几个框架的汇编代码,有可能该数据还在堆栈的某个地址上。静态变量是储存在固定地址中的,所以找出静态变量的值较为容易。.Frame(或者在调用堆栈窗口中双击)可以用来切换当前的框架。注意dv命令显示的是当前框架的内容。你也可在watch窗口中观察局部变量的值。显示类和链表: dt可以显示数据结构。比如dt PEB 会显示操作系统进程结构。在后面跟上一个进程结构的地址会显示该结构的详细信息:dt PEB 7ffdf000。Dl命令可以显示一些特定的链表结构。显示当前线程的错误值:!gle会显示当前线程的上一个错误值和状态值。!error命令可以解码HRESULT。搜索或修改内存:使用s 命令来搜索字节,字或双字,QWORD或字符串。使用e命令来修改内存。计算表达式:?命令可以用来进行计算。关于表达式的格式请参照帮助文档。使用n命令来切换输入数字的进制。显示当前线程,进程和模块信息:!teb显示当前线程的环境信息。最常见的用途是查看当前线程堆栈的起始地址,然后在堆栈中搜索值。!peb显示当前进程的环境信息,比如执行文件的路径等等。lm显示进程中加载的模块信息。显示寄存器的值:r命令可以显示和修改寄存器的值。如果要在表达式中使用寄存器的值,在寄存器名前加@符号(比如@eax)。显示最相近的符号:ln Address。如果你有一个C++对象的指针,可以用来ln来查看该对象类型。 查找符号:x命令可以用来查找全局变量的地址或过程的地址。x命令支持匹配符号。x kernel32!*显示Kernel32.dll中的所有可见变量,数据结构和过程。查看lock:!locks显示各线程的锁资源使用情况。对调试死锁很有用。查看handle:!handle显示句柄信息。如果一段代码导致句柄泄漏,你只需要在代码执行前后使用!handle命令并比较两次输出的区别。有一个命令!htrace对调试与句柄有关的Bug非常有用。在开始调试前输入:!htrace –enable 然后在调试过程中使用!htrace handle_value 来显示所有与该句柄有关的调用堆栈。显示汇编代码:u。程序执行控制命令:设置代码断点:bp/bu/bm 可以用来设置代码断点。你可以指定断点被跳过的次数。假设一段代码KERNEL32!SetLastError在运行很多次后会出错,你可以设置如下断点: bp KERNEL32!SetLastError 0x100.在出错后使用bl 来显示断点信息(注意粗体显示的值):0 e 77e7a3b0 004f (0100) 0:*** KERNEL32!SetLastError重新启动调试(.restart命令)并设置如下的断点:bp Kernel32!SetLastError 0x100-0x4fDebugger会停在出错前最后一次调用该过程的地方。你可以指定断点被激活时Debugger应当执行的命令串。在该命令串中使用J命令可以用来设置条件断点:bp `mysource.cpp:143` "j (poi(MyVar)”0n20) ""; "g" "上面的断点只在MyVar的值大于32时被激活(g命令条件断点的用途极为广泛。你可以指定一个断点只在特殊的情况下被激活,比如传入的参数满足一定的条件,调用者是某个特殊的过程,某个全局变量被设为特殊的值等等。设置内存断点:ba可以用来设置内存断点。调试过程中一个常见的问题是跟踪某些数据的变化。如下的断点:ba w4 0x40000000 "kb; g"可以打印出所有修改0x40000000的调用堆栈。控制程序执行:p, pa,t, ta等命令可以用来控制程序的执行。控制异常和事件处理:Debugger的缺省设置是跳过首次异常(first chance expcetion),在二次异常(second chance exception)时中断程序的执行。sx命令显示Debugger的设置。sxe和sxd可以改变Debugger的设置。 sxe clr可以控制Debugger在托管异常发生时中断程序的执行。常用的Debugger事件有: av 访问异常 eh C++异常 clr 托管异常 ld 模块加载-c 选项可以用来指定在事件发生时执行的调试命令。

电脑蓝屏windbg检测到!analyze -v的问题,怎么弄啊?

ntoskernel.exe内核进程出现问题自然导致蓝屏,日志可以贴详细一些,看看到底是啥导致了ntoskernel出现问题
 首页 上一页  1 2