操作系统的调试符号路径:
SRV*D:\symbols*http://msdl.microsoft.com/download/symbols;D:\MyAppSymbol
D:\symbols--标识本地保存下载后的符号路径
http://msdl.microsoft.com/download/symbols--微软提供的操作系统符号下载路径
D:\MyAppSymbol--表示自己编译产生的符号文件路径。
符号之间用分号隔开。
一:利用堆栈来发现信息:
kb --显示堆栈信息,从堆栈信息可以看出调用函数的返回地址,函数参数信息。
kn --n这个参数是用来显示frame number的。
通过上述参数信息,如果是调试临界区死锁可以使用一下命令:
!cs [参数地址] -- 该命令可以看到拥护该临界区的id号(owning thread:***)
~~[***] --该命令通过获取到的id号(owning thread:***)来转换成线程TID。
然后调试说获取到的TID,用上述类似的方法步骤查看该TID在等待那个临界区,这个临界区由那个线程所拥有
获取参数中的内容,比如MessageBox函数的第一个参数。
da 第一个参数的内存地址
.frame /number/ -- 定位到某个frame number上
x -- 显示当前frame相匹配的符号信息
dt /变量/ -- 格式化显示资料信息
二:dds命令[打印内存地址上的二进制值,同时自动搜索二进制值对应的符号]
dds ebp -- 查看当前stack中保存了那些函数地址,就可以检查ebp指向的内存。
还有如何打印出com vtable函数信息:
0:000>x ole32!OpaqueDataInfo::'vftable'
7768265c ole32!OpaqueDataInfo::'vftable' = <no type information>
77682680 ole32!OpaqueDataInfo::'vftable' = <no type information>
0:000>dds 7768265c
7768265c 77778245 ole32!ServerLocationInfo::QueryInterface
三:查看当前执行的指令
u eip
四:内存相关调试
pageHeap启动与否,在memory窗口中看到的信息不一样
pageHeap启动:>pageHeap /enable mytext.exe /full
检查启动情况:>pageHeap
pageHeap无法保证发现所有潜在问题,工作原理就是保证分配的单元数目是4kb的整数倍。
五:三种常见的问题[句柄泄漏,死锁,线程争用]
句柄泄漏:观察handle增长情况,增长handle的类型,是什么时候创建的。
!handle, !handle /handle number/
死锁: 往往是在waitForSingleObject或者是EnterCriticalSection上不返回。
1:kb -- 获取参数信息
2:!cs 参数 --获取owningThreadID
3:~~[ThreadId] -- 转换成TID
4:切换线程用上述方法查看用户临界区的线程
若 3 出现以下错误:
0:001>~~[0x000014c4]
^Illegal thread error in '~~[0x000014c4]'
可以使用application verifier工具勾选Lock,运行,捕获异常。
线程争用:
性能问题:[解决该问题的关键是找到出现瓶颈的地方]
1:CPU的利用率是关键。
CPU利用率高的几种情况:
第一:程序出现了死循环,
第二:如果CPU利用率一直很高,且响应时间随负荷增加而变长,当负荷下降后性能又恢复正常。
解决的办法是升级硬件或者增加服务节点。
第三:(待续)
对于出现Assess Viloation异常分析的经验。
对于发生Access Viloation异常,打出的堆栈一般有这么几种比较重要的信息显示:__except_handle4(***), __except_handle3(***), __CxxUnhandleExceptionHandle(***)。
一般来说就这三种形式。
利用
kp.--函数参数信息
kv.--参数值信息
kn.--栈帧信息编号
你就可以看到很重要的信息,注意struct _EXCEPTION_RECORD*, struct _CONTEXT*这两个结构参数。而对于_C**UnhandlerExceptionHandle是由一个
Struct Exception_Pointer 结构体,该结构体定义如下:
Struct Exception_Pointer
{
PEXCEPTION_RECORD pRecord;//里面又包含如exceptionCode, exceptionFlag等等。
PCONTEXT pContext; //这个也是一个结构体
}
所以对于_CXXUnhandlerExceptionHandler,就需要先使用dd命令来获取Exception_Pointer包含的两个数据成员的地址。
获取完这两个地址,我们就可以通过.exr和.cxr命令来参看具体发生了什么异常,发生异常时上下文信息情况。这个时候幸运时,可以看到发生crash时的源代码,
有时候还不会有很大的帮助。
还可以继续尝试在此上下文信息运行kn命令,有时会有意想不到的信息出现,也许这就是你需要的信息。
如果kn运行后,有堆栈出现,你还需要获取进一步的信息。
可以再次尝试使用 “.frame 编号”(不包括双引号)和 “x”,查看当前栈帧局部变量情况。同时最好打开watch窗口。
如果上述方法均不行,你还可以通过查看发生该问题的线程及日志来跟踪调查。运行ALT+9快捷键,将黑体加粗的线程对应的数字从16进制转换层十进制,就是线程号。
根据获取的线程号,来查看对应的日志。
2:WARNING: Unable to verify timestamp for ××.dll
ERROR: Module load cdompleted but symbols could not be loaded for **.dll
看到类似以上信息是要格外注意,如果加载不正确的信息,后面所有的命令都是很难说明问题的。这是windbg的根本,所以发布版本的时候一定要保存好自己的源代码及符
号文件。
利用 "lm v" 命令(不包含双引号)来查看发生dump捕获下来模块信息。利用显示的信息来与你加载符号的文件信息进行核对,看时间戳是否一致,如果不一致,那就找到对应
的模块才做接下去的工作。
"lm v"是查看所有加载模块的具体信息,时间较长,如果需要参看某一模块信息,可以使用扩展命令“!lmi 模块名”。
3:利用windbg参看发生dump发生的时间。
打开Dump文件:你会看到Debug session time:***这样的信息,这就是发生dump的时刻信息。有了这个信息,你查看日志就有更加方便。