您的位置:首页 > 其它

调试文档整理

2008-04-21 23:43 309 查看
本文档包括三部分的内容:

第一节 基本原理和概念

第二节 常用工具使用说明

第三节 参考文档

第一节 基本原理和概念

1. CPU和操作系统为调试提供的支持。

1) 中断

中断是整个操作系统的基础机制。

处理突发事件,满足实时要求,实现并行工作,请求系统服务 这些都需要打断处理器正常的工作,于是提出了中断的概念。

中断就是在程序执行过程中,当发生某个事件时,中止CPU上现有程序的执行,引出处理该事件的程序执行的过程。

2) 异常

中断按照不同的标准可以有不同的分类。

从中断事件的性质和激活的手段来说分为强迫性中断,自愿性中断。

强迫性中断事件不是正在运行的程序所期待的,而是由于某种事故或外部请求信息所引起的。如机器故障,外部中断,输入输出中断事件,程序性中断。自愿性中断是正在运行的程序所期待的事件。如访管指令 。

按照中断事件的来源来说分为 外中断,内中段。

外中断是指CPU和内存以外的中断,内中断是CPU和内存所引起的中断。

我们平时所说的狭义的中断是指外中断。

内中断又称为异常。内中断指通路校验错、主存奇偶错、非法操作码、地址越界、页面失效、调试指令、访管中断、算术操作溢出等各种程序性中断。

中断(外中断)和异常(内中断)有什么区别

中断是一个异步的事件,跟现在执行指令无关的中断信号触发。两条机器指令之间才可以响应这种中断。一般来说中断处理程序提供的服务跟当前进程无关。

异常是一个同步的事件,是由现在执行的指令引起的。

一条指令执行期间就可以响应异常,异常处理程序提供的服务是为当前进程所需要的。

异常又可以分为两类,一个是出错(fault) ,另外是陷入(trap).

两者的主要区别是异常发生时保存的返回指令的地址不同。

出错保存的返回地址是触发异常的那条指令,也就是说,执行完出错处理程序后,引发出错的那条指令还会重新执行,而陷入保存的返回地址是触发异常指令的下一条指令的地址,也就是说执行完陷入处理程序后,从引发陷入的指令的下一条指令开始执行。例如我们平时遇到的缺页就是一种fault,而调试器里面的单步执行就是一种Trap.

3) 综述

总之是CPU提供了一些调试指令供我们使用。通过中断机制,控制权可以从CPU,传递到操作系统,而操作系统又可以通知给调试器,最终我们跟调试器交互来控制我们正在调试的程序,如单步执行,一个函数一个函数的执行,抓dump等等。上面说了那么些都是为了说明三者之间的关系。

2. 几个比较重要的概念

1) First chance exception ,Second chance exception

这两个概念是只有在调试的时候才出现的,而实际上异常并没有first chance,second chance 之分。

当cpu执行到错误的指令出现异常时,发生了中断,通过中断机制,引发操作系统提供的异常处理程序的执行,异常处理程序发现这个进程正在被调试器调试着,把相关的信息发给调试器,我们这个时候收到first chance exception .我们可以根据实际的需要做一些操作,如查看函数调用堆栈,抓mini dump,抓full dump ,观察某些值,改写某些值等等。注意:这些操作都发生在我们自己代码里面提供的异常处理程序执行之前。

我们做完了这些后,如果把控制权从调试器返回给操作系统,操作系统通过结构化异常处理的机制,来找我们代码里面的异常处理程序,也就是Catch块。如果找到了,我们的调试器就不会再收到second chance exception 了,如果没有找到,操作系统把控制权又返回给调试器 ,也就是给你第二次机会来处理这个异常,我们这个时候又可以做一些事情。当控制权返回给操作系统后,操作系统发现这个异常没有被处理,会调用操作系统提供的默认的异常处理程序,然后就crash掉了。

2) FailFast

FailFast可以说是一种编程的思想,就是指当发生错误时,尽快的把程序给结束掉,避免程序继续运行造成更大的破坏。Com+就实现了failfast。在com+ 里面我们永远不会收到second chance exception 。原因是我们组件代码的运行被封装在了一个try catch 块里面了。也就是说当我们的组件代码发生异常时,即使我们没有提供自己的异常处理,com+里面的catch块也要执行。Com+的运行环境也是一个进程,按照上面我们说的,我们就不会收到second chance exception .

知道这些对我们有什么用呢,是这样的,我们抓dump的时候,一般抓的是full dump,full dump 一般比较大,我们一般是 second chance exception 发生时抓.因为first chance exception 发生的比较多,有很多是系统里面的,对我们没有多大的意义。但是com+里面我们收不到second chance exception ,按照通常的方法,我们就抓不下dump来了。

但是com+也提供了另外一个机制,就是当发生fail fast 的时候,我们可以收到另外一个事件就是debug break .我们可以设置调试器当收到这个事件时去抓full dump。这样的话就可以在收不到second chance exception 的条件下抓full dump 了。

3) Pageheap

pageheap.exe 有两种模式normal,full。这两种模式处理的情况不同。normal 是通过添加验证字符的形式。这种只有在破坏了堆结构以后,再次使用堆的时候,才会触发异常。full 是通过在分配内存的前后添加不可读内存块的形式来验证。这种方式只要破坏了堆结构,立刻就会触发异常。还有堆分配的粒度问题。如申请分配10个字节。往11的位置写字符是不会触发异常的。

第二节 常用工具使用说明

1. Debugging Tools for Windows

1) 我们一般使用这个工具里面的UI界面的调试器 windbg和adplus.vbs这个脚本。

遇到问题时处理的基本思路:

观察问题的症状,如果是程序崩溃,我们要用adplus 的crash 参数来抓dump.

如果是程序挂起,我们用hang参数来抓。这些都是初步的判断,实际情况要复杂的多,例如我们GS里面的com+挂起,根据症状我们用Hang来抓,分析dump后发现是由于

Heap curruption导致的,我们还要用crash来抓。

要注意adplus支持配置文件这个参数,我们可以在配置文件里面指定当发生一些事件时调试器自动进行的操作。Adplus 有很多参数了,在dos窗口下面执行一下就知道是什么意思了。不多说了。

2)

Windbg是一个UI界面的调试器,支持用户态程序调试和内核程序调试,我们平时用的都是User mode 调试。这个工具一个很大的好处是,如果你有一些工作比较繁杂,可以写一个dll扩展,然后可以直接调用你的这个dll里面的命令来做一些处理。我们使用windbg的第一步一般是设置一下调试符号的路径.通过Ctrl+S 来完成。

srv*DownstreamStore*http://msdl.microsoft.com/download/symbols

其中DownstreamStore 为自己磁盘上面的某个文件夹。后面的Url是微软的公共调

试符号文件下载地址。

3) 常用的命令

Ø !analyze –v 这个自动分析dump里面出现的问题。

Ø lm 查看当前的进程都加载了哪些dll

Ø lmvm dll名字 查看某个dll的详细信息,用这个命令可以看某个dll的调试符号文件是否已经加载了。

Ø ld [ModuleName] 加载某个dll的调试符号。

Ø .reload 重新加载某个dll. 我们经常用的参数是 /f /i 分别是强制加载和忽略调试符号文件版本不匹配。

Ø dv 显示局部变量的值 dv /v 显示局部变量的值和地址

显示局部变量也可以用dd 局部变量的名字来实现。内容的左列就是变量的地址

也可以用x 命令 examine sysbols ,输出一个模块中的类型可以用dt ,如

dt ntdll!*

dt -b 可以列出一个数据结构的所有信息,包括子结构的信息。

Ø ~ 列出所有的线程。

Ø ~ * Kb200 列出所有线程的调用堆栈

Ø uf 反编译某个函数。

Ø uf address 从某个地址开始反编译某个函数.

Ø Kb200 列出当前线程的调用堆栈。

Ø .exr exception address 查看异常的具体信息。

Ø .cxr 切换堆栈上下文

Ø .exr .cxr 我们经常用到

在一些函数的参数里面我们能找到这样的结构。

typedef struct _EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; PCONTEXT ContextRecord;

} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

假设参数地址 ox888888888吧,然后 dd ox888888888 ,开始的两个地址分别是 异常信息的地址和上下文的地址用 .exr 看异常的详细信息用 .cxr 切换上下文环境。切换上下文后用KB可以看当时出错的调用 stack 了.

4)

真正分析一个dump还是比较难的,一些技巧需要专门的训练。首先要明白函数调用在汇编的层次是怎么实现的,这个中科大那边编译原理有一章专门讲了,看看也就清楚了。具体函数反汇编出来的代码怎么看比较难,如果debug版本没有经过优化还是比较简单的,有本书<<黑客反汇编揭秘>> 可以参考一下,参数怎么传,用哪些寄存器来完成,对象,方法表,返回值等等都有说明。但是现在的编译器优化技术越来越好了,很可能我们写的时候是这样,真正编译出来就变了,release版本的程序反汇编就很难看了。还有我们碰到的一般是有问题的程序,很可能调试器显示的调用堆栈也是错误的,调试器是很蠢的,他就是按照某些算法来给你生产函数的调用关系,如果数据被破坏了,调用堆栈也不一定是正确的。

5) 关于这个工具最好的参考文档还是他们提供的帮助文档。

2. DebugDiag 1.1 (x86)

这个工具本来是专门针对IIS的问题微软开发的一个工具,但他的功能比较强大,可以用在很多地方。从程序主界面上看有三个tab .主要功能这就是三个。

1) Rules

自己定义一些规则。当被观察的进程达到某些条件的时候,调试器可以做一些相应的动作。我们用到的就是观察一个进程的内存,如达到某个值后,我们可以抓dump,然后来分析这些dump. 其实远不止这些,因为里面一些事件,异常的处理动作是可以自己定义的,并且这个自定义是可以写脚本来完成的,vbs脚本,这个工具本身提供了很多对象,具体可以看帮助文档。

2) Advanced Analysis

可以分析我们抓的dump文件。

3) Processes

列出系统里面的进程,我们可以结束进程,抓dump等等。

3. PageHeap 。

这个工具是用来设置系统变量的,用来指定某个进程堆内存的分配情况。

4. Map2dbg

这个工具用来把map符号文件转化为dbg格式的调试符号文件。

第三节 参考文档

1.《Microsoft.NET和Windows应用程序调试》

讲了调试器的原理,里面有作者自己写的一些工具,包括一个可以使用的调试器。

2. Production Debugging for .NET Framework Applications

微软的一份调试指南,专门讲dotnet 生产环境下的调试

3.熊力的那本书。<<windows 用户态程序高效排错>>

4.网上面的资料也很多,主要是国外的。

国内的有个http://advdbg.com/ 论坛上面的人很热情,基本上有问必回。

这个论坛上面有个人今年也要写一本书了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: