您的位置:首页 > 其它

《软件调试》学习笔记——004 (第一章 软件调试基础 part2)

2012-01-10 20:40 316 查看
《软件调试》学习笔记——004(第一章软件调试基础part2)

常用软件调试技术:

1)断点(Breakpoint)

断点和单步执行是最基本的调试手段。其基本思想是让被调试程序在执行到该处时,暂停被调试程序的执行;中断到调试器中,让调试人员进行分析。分析结束后,可以让被调试程序继续执行。

根据断点所处的空间,可以分为以下3种断点:

代码断点

设置在内存空间的代码段(即,断点地址为代码段的某个地址),当CPU执行该地址时,断点命中,中断到调试器。在源代码上(xx文件xx行)设定的断点都是代码断点。
数据断点

断点地址为数据段的某个地址,某个变量或数据的起始地址。当CPU访问该地址的数据时,断点命中,中断到调试器。

根据需要,可以定义触发断点的访问方式(读/写)、宽度(BYTE,WORD,DWORD)。

[EasyVCR@csdn]

怎样设置数据断点?

gdb:可以通过watchpoint来设置,当某个变量值改变(写)时中断到调试器;(gdb)helpwatch

WinDBG:???

I/O断点

断点地址为某一I/O地址。当CPU访问该I/O地址的端口时,断点命中,中断到调试器。

和数据断点类似,也可设置断点被触发的访问宽度(BYTE,WORD,DWORD)。

根据断点的设置方法可以,可以分为软件断点和硬件断点:

软件断点

软件断点通过向断点所在位置插入断点指令来实现。不同平台的断点指令可能不同。比如IA32架构CPU的断点指令为INT3(其对应的机器码为0xCC)。

断点指令只能设置上面提到的代码断点;而不能设置数据断点或者I/O断点。

[EasyVCR@csdn]

VC的Debug版程序,所有的局部变量都被初始化为0xCC;这样当程序"跑飞",将数据作为代码来执行时,就会解析成断点指令,如果是在调试器下被调试,就会中断下来;如果不是以被调试模式运行,操作系统也会给你一个选择加载调试器调试的机会。

而Release版的程序,局部变量被初始化为0x00;当程序"跑飞"时,操作系统也不会解析成断点指令。这也是Debug和Release版程序在运行时表现不一致的一个重要方面。

硬件断点

硬件断点通过CPU的调试寄存器设置。IA32架构CPU定义了8个调试寄存器(DR0~DR7)。对同一个调试会话,最多可同时设置4个硬件断点。

当中断到调试器时,被调试程序是处于【静止】状态。调试器会将被调试程序的状态保存到执行上下文(CONTEXT)中;当用户输入恢复执行的调试命令时,调试器再恢复被调试程序,使其继续运行。

[EasyVCR@csdn]

这个过程相当于自定义一个SuspendOrResumeProcess函数(遍历被调试进程中的所有线程,然后调用SuspendTread)




voidSuspendOrResumeProcess(DWORDdwPID,BOOLbSuspend) { HANDLEhSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,dwPID); if(INVALID_HANDLE_VALUE!=hSnapshot) { THREADENTRY32te32={sizeof(THREADENTRY32)}; BOOLbFind=Thread32First(hSnapshot,&te32); for(;bFind;bFind=Thread32Next(hSnapshot,&te32)) { if(te32.th32OwnerProcessID==dwPID) { HANDLEhThread=OpenThread(THREAD_SUSPEND_RESUME,FALSE,te32.th32ThreadID); if(NULL!=hThread) { bSuspend?SuspendThread(hThread):ResumeThread(hThread); } CloseHandle(hThread); } } CloseHandle(hSnapshot); } }


ps,采用这种遍历线程的方式,对多线程程序,可能会导致各个线程中的执行情况与真实运行时有差异。

可能需要直接调用ntdll中的ZwSuspendProcess/ZwResumeProcess来挂起/恢复整个进程。

下图是Depends看到的ntdll的导出函数列表





typedefDWORD(WINAPI*PFSuspendProcess)(HANDLEhProcess); typedefDWORD(WINAPI*PFResumeProcess)(HANDLEhProcess); voidSuspendOrResumeProcess(DWORDdwPID,BOOLbSuspend) { HMODULEhNtDllLib=LoadLibrary(TEXT("ntdll.dll")); PFSuspendProcessSuspendProcess=(PFSuspendProcess)GetProcAddress(hNtDllLib,"ZwSuspendProcess"); PFResumeProcessResumeProcess=(PFResumeProcess)GetProcAddress(hNtDllLib,"ZwResumeProcess"); if(SuspendProcess&&ResumeProcess) { HANDLEhProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID); bSuspend?SuspendProcess(hProcess):ResumeProcess(hProcess); CloseHandle(hProcess); } FreeLibrary(hNtDllLib); }

追踪点与条件断点

追踪点(Tracepoint)

一种特殊的断点,当调试器中断到追踪点时,自动执行预先定义的追踪行为(通常为收集信息,比如打印某些变量的值),然后立即自动恢复被调试程序,使其继续运行。

[EasyVCR@csdn]

gdb:(gdb)helptracepoints

WinDBG:怎样设置Tracepoint?

条件断点(ConditionalBreakpoint)

一种特殊的断点,仅当定义的条件被满足时,调试器才中断被调试程序,让调试人员进行调试。

实际上,对调试器而言,每次执行到条件断点都会中断,只是中断后处理的行为不同:如果不满足条件断点定义的条件,则立即恢复被调试程序继续运行(调试人员感觉不到);如果满足,则中断被调试程序,让调试人员进行调试。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: