Windows用户态调试技术

  • 一、工具使用

1.1产生dump工具比较
有5种产生用户态dump文件的工具,包括ADPlus、Dr.Watson、CDB 和、WinDbg和userDump。
其中ADPlus是目前最好的工具。抓crash的具体命令为:
adplus.vbs -crash -pn TMSACSDm.exe -fullonfirst -o c:\dumps
注意必须在进程起起来后,并在crash之前启动ADPlus。

1.2WinDbg设置symbol环境变量和路径_NT_SYMBOL_PATH=srv*c:\mysymbols*http://msdl.microsoft.com/download/symbols;cache*c:\mysymbols
同时,在WinDbg中设置Symbol File Path为同样的值。

1.3PDB文件
PDB文件为符号文件,包含了二进制文件的调试信息,符号文件包括全局变量、局部变量、函数名和它们的入口地址、FPO(Frame Pointer Omisson)数据。Frame Pointer是一种用来在调用堆栈中找到下一个将要被调用的函数的数据结构源代码的行序号。1.2节设置的路径就是用来查找PDB文件的,包括系统的符号文件,将从微软网站自动下载。【url:http://www.vckbase.com/index.php/wv/1418.html符号文件——Windows 应用程序调试必备】
WinDbg系列工具中symchk.exe可用于检查exe和pdb文件是否匹配
symchk.exe TMSACSDm.exe /v /s ./
[url: 关于PDB与EXE/DLL 文件的匹配问题:
http://blogold.chinaunix.net/u/8681/showart_2217695.html]

  • 二、测试实例

2.1进程Crash实例
(1)将软件对应pdb文件,包括dll和lib的pdb文件拷贝到c:\mysymbols中
(2)开启进程
(3)运行adplus.vbs -crash -pn TMSACSDm.exe -fullonfirst -o c:\dumps
(4)进程crash
(5)查看c:\dumps下dump文件
(6)windbg->file->Open Crash Dump
(7)!analyze –v综合分析crash情况
(8)kb显示堆栈
(9)ln addressA,显示addressA地址附近的符号

2.2利用map和cod文件找到崩溃地址对应代码
(1)设置linker-debugging-Generate Map File 为 YES
(2)设置C/C++-Output Files-Assembler Output 为 Assembly, Machine Code and Source (/FAcs)
(3)从map文件中,找到比崩溃地址(0x00411a84)小的最大的地址(0x00411a30),从而找到崩溃的函数名
(4)用崩溃地址减去崩溃函数地址,得到偏移地址(0x54),从cod文件中找到偏移地址为0x54的行,发现对应的代码行为(int b = 123/a;)
[url: http://blog.csdn.net/zhuzhu101011/article/details/4257108利用map和cod文件查出崩溃代码行]
// test123.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	int a = 0;
	int n = 30000;
	while( n )
	{
		printf( "n is %d\n",n );
		n--;
	}
	int b = 123/a;
	return 0;
}


2.3进程消耗CPU实例
(1)通过任务管理器,找到消耗CPU多的进程
(2)用windbg附上这个进程
(3)!runaway 3显示每个线程用户模式和内核时间
(4)g运行一段时间,然后ctrl+c再次暂停程序
(5)再次运行!runaway 3,显示每个线程消耗的时间。对比两次!runaway 3命令的运行结果,可以得出消耗CPU最多的线程是哪个
测试程序如下:[http://blog.csdn.net/hgy413/article/details/7564252 Windbg命令学习6(!runaway和~)]
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

DWORD WINAPI thread_fun1(LPVOID n)
{
   while(1)
   {
	   printf( "thread_fun1\n" );
   }
}

DWORD WINAPI thread_fun2(LPVOID n)
{
	Sleep(10000);
}

DWORD WINAPI thread_fun3(LPVOID n)
{
	Sleep(5000);
}

int main()
{
	HANDLE hThrd;
	DWORD threadId;


	
	hThrd = CreateThread(NULL,
		0,
		thread_fun1,
		(LPVOID)1,
		0,
		&threadId);
	printf("Start the first thread[%d]\n",threadId);
	
	hThrd = CreateThread(NULL,
		0,
		thread_fun2,
		(LPVOID)1,
		0,
		&threadId);
	printf("Start the second thread[%d]\n",threadId);

	hThrd = CreateThread(NULL,
		0,
		thread_fun3,
		(LPVOID)1,
		0,
		&threadId);
	printf("Start the third thread[%d]\n",threadId);

	while(1)
	{

	}
}


2.4判断死锁hang住问题
(1)将windbg附到挂住的进程
或者使用ADPlus -hang -pn dead_mutex_lock.exe –o C:\dumps将dump保存下来
(2)用命令~显示所有的线程
(3)然后~ns命令将第n个线程设定为当前线程
(4)最后kb显示当前线程的调用栈
具体例子见:
#include <windows.h>
#include <stdio.h>

HANDLE hMutex1;
HANDLE hMutex2;


DWORD WINAPI thread_fun1(LPVOID n)
{
	WaitForSingleObject(hMutex1,INFINITE);
	Sleep(1000);
	WaitForSingleObject(hMutex2,INFINITE);
	printf("mutex 1 -->  mutex 2 is running\n");
	ReleaseMutex(hMutex2);
	ReleaseMutex(hMutex1);
}

DWORD WINAPI thread_fun2(LPVOID n)
{
	WaitForSingleObject(hMutex2,INFINITE);
	WaitForSingleObject(hMutex1,INFINITE);
	printf("mutex 2 ---> mutex 1 is running\n");
	ReleaseMutex(hMutex1);
	ReleaseMutex(hMutex2);
}

int main(int argc, char argv[] )
{
	HANDLE hThrd;
	DWORD threadId;

	hMutex1=CreateMutex(NULL,FALSE,"tickets1");
	hMutex2=CreateMutex(NULL,FALSE,"tickets2");

	hThrd = CreateThread(NULL,
		0,
		thread_fun1,
		(LPVOID)1,
		0,
		&threadId);

	hThrd = CreateThread(NULL,
		0,
		thread_fun2,
		(LPVOID)1,
		0,
		&threadId);
	Sleep(100000);
}

猜你喜欢

转载自braveyly.iteye.com/blog/1664902