调试器是否已连接?






4.96/5 (12投票s)
2001年10月23日
3分钟阅读

146751

672
根据调试器是否附加到您的进程,采取不同的操作。
引言
是否附加了调试器? 我的大部分工作是作为一名bug终结者,我倾向于在我的项目中需要更多的调试或调试支持代码。 本文的代码实质只是一个小函数,实际上大约有13行代码。 看起来微不足道,但对于我这样经常进行调试的人来说,它非常有用,当然,我甚至编写这个函数本身也很有趣。
详细说明
该函数被称为 IsDebuggerAttached()
。 顾名思义,如果调试器附加到进程,它会返回一个 BOOL
指示。 这是在Windows NT 4.0上开发并针对该系统开发的,并且也适用于Windows 2000。 我不知道它是否适用于Win9x,因为内部Windows结构不同。 我现在将深入探讨我需要它的原因示例,以及它如何帮助可能也有此类需求的其他人。
我将验证和验证进入函数的参数视为良好编程实践的支柱之一。 更重要的是,指针的验证。 由于在过去的几年软件工程中缺乏这种实践,我一直有稳定的“业务”来源。 在某些情况下,进入函数的参数应始终有效。 在这种情况下,要做的标准事情是通过 ASSERT
's 检查参数的有效性。 这非常适合永远不会使断言失败的参数。 关于断言的伟大之处在于,它使您可以选择中断到调试器中。 就发布版本而言,这是不可用的,因为 ASSERT
's 的计算结果为无。
在某些情况下,我决定希望根据调试器是否附加到我的进程来采取不同的操作。 如果没有附加调试器,我的代码要么在非常糟糕的情况下弹出消息框,要么输出调试字符串,并在可能的情况下安静地继续运行。 但是,我还希望它能够在附加调试器的情况下在错误条件的位置中断。 显然,我不想构建一个弹出消息框和/或输出调试字符串的代码版本,以及另一个执行 DebugBreak()
的版本。 此外,如果您调用 DebugBreak()
并且调试器未附加到您的进程,系统会弹出一个令人讨厌的对话框,指示调试中断异常。
总而言之,这显然是我想要的
if (Big_Bad_Error) { if (Debugger_Is_Attached) { Break_Into_Debugger; } else { Say_Something; } }
这是函数 IsDebuggerAttached()
的代码
BOOL IsDebuggerAttached() { DWORD dw; __asm { push eax // Preserve the registers push ecx mov eax, fs:[0x18] // Get the TIB's linear address mov eax, dword ptr [eax + 0x30] mov ecx, dword ptr [eax] // Get the whole DWORD mov dw, ecx // Save it pop ecx // Restore the registers pop eax } // The 3rd byte is the byte we really need to check for the // presence of a debugger. // Check the 3rd byte return (BOOL)(dw & 0x00010000 ? TRUE : FALSE); }
这是深入挖掘进程的线程信息块 (TIB),以检查是否附加了调试器。 对于那些还不知道的人,FS 寄存器指向当前线程的 TIB。 不用说,达到这一点的过程涉及在调试器中对 Windows 进行大量的反汇编。 下面是本文示例应用程序中的代码。 这是一个 MFC 对话框应用程序,其中测试在 OnOK()
处理程序中完成
void CDebuggerDlg::OnOK() { LPBYTE lpBuffer = (LPBYTE)0x80000000; // Give it a bogus buffer that will crash it for sure ReadMemory(lpBuffer, 1024); } BOOL CDebuggerDlg::ReadMemory(LPVOID lpBuffer, DWORD dwSize) { // Validate the buffer if (IsBadWritePtr(lpBuffer, dwSize)) { // This is bad! Must say something! if (IsDebuggerAttached()) { // So we'll break into the debugger __asm int 3 // If you don't mind the function call overhead, // you can call DebugBreak(); // instead... } else { MessageBox( "CDebuggerDlg::ReadMemory() : " "Bad output buffer : lpBuffer!"); } return FALSE; } // Well, we're not really gonna write anything to the buffer, // it's just a demo ;) return TRUE; }
各位,我希望这项技术对你们中的一些人有所帮助。