调试时,有时需要附加已经运行的进程,而不是仅在调试器中启动应用程序。
我自己常常输入Sleep()或MessageBox调用,以便更容易连接调试器。我担心其中一些可能最终会被提交给源代码控制。
在延迟足够时间的同时避免这种情况的最佳方法是什么,以便将调试器连接到正在运行的进程?
使用#ifdef _DEBUG
保护睡眠或消息框是一种方式,但我想知道是否有更好的方法。
有了睡眠,您也会遇到可能无法及时附着的问题。使用MessageBox,您可能会遇到远程调试或调试没有可见GUI的进程的问题(例如在Vista上作为服务运行)
答案 0 :(得分:11)
您可以使用DebugBreak,请检查以下链接:
http://www.epsilon-delta.net/articles/vc6_debug.html#breaking-with-debugbreak
http://blogs.msdn.com/calvin_hsia/archive/2006/08/25/724572.aspx
答案 1 :(得分:9)
要在特定点附加调试器,您有以下几种选择:
最简单的只是调用DebugBreak
,它几乎等同于__asm int 3
,但也适用于其他架构(如果我没记错的话,MSVC for x64不允许内联汇编)。这将打开即时调试器窗口,您将能够从已注册的调试器(即Visual Studio)中进行选择以附加到该过程。
或者,您可以调用Sleep
,让您有机会附加调试器。您应该在此周围使用#ifdef _DEBUG
,以确保您实际上并未附带此代码。
一个问题:为什么不能从IDE运行代码?它是服务还是IIS加载的DLL或类似的?
在这种情况下,您可以查看ImageFileExecutionOptions
注册表项,该注册表项允许您在进程启动时附加调试器。
如果您使用cdb,则可以将其配置为WinDbg实例的服务器或客户端,并以此方式进行调试。我以前使用WinDbg作为内核调试器,并使用ImageFileExecutionOptions用命名进程启动ntsd -d
来完成此操作。这会导致WinDbg进入用户模式。这有时是一种有用的技术。
答案 2 :(得分:7)
另一种变体,我有时使用
while( !::IsDebuggerPresent() )
::Sleep( 100 ); // to avoid 100% CPU load
它应该静静等待,直到您将调试器附加到进程。
答案 3 :(得分:6)
仅显示MessageBox会部分停止您的应用程序。因为您正在显示UI,所以程序中至少有一个线程仍在运行消息泵。因此,如果您的代码执行以下任何操作。
您实际上将在一个状态下请求调试器,但在完全不同的状态下附加到您的程序。这可能会导致令人困惑的情况和错误。
我们最近对我们的代码库进行了更改,以便永远不会显示MessageBox,以便为此提供便利。它会为非平凡的应用程序产生非常糟糕的行为。
答案 4 :(得分:2)
必须附加'恰到好处'是一种痛苦...一种选择是将明确的DebugBreak()语句添加到代码中以强制解决问题,并用#ifdef _DEBUG
保护它们会很好理念。我们使用可以调用DebugBreak()的ASSERT宏,因此您只需编写ASSERT(false)
答案 5 :(得分:1)
向上看:
DebugBreak,__ decugug和朋友
或
static void timeToChase(){__ asm {int 3; }; }
答案 6 :(得分:1)
__asm int 3
这个硬断点将打开调试对话框,它将允许您附加到进程。在#ifdef _DEBUG中包装,你只能在调试版本中点击它。
答案 7 :(得分:1)
如果__debugbreak()或DebugBreak()适合您,那么我认为这可能是最好的方法。
但是,由于某些未知原因,我遇到了__debugbreak()只是立即终止程序而不是等待调试器连接的情况。我尝试了各种方法来解决此问题(注册表黑客等),但似乎没有任何效果。 (在这种情况下,我尝试调试的过程可能不是直接从命令行启动,而是由Java程序启动的。)
无论如何,在那种情况下,我使用了这种方法,效果似乎很好:
void waitForDebuggerToConnect() {
#ifdef _DEBUG
static volatile bool spin = true;
while (spin)
{}
#endif
}
调用此函数后,我的程序将无限期地挂在“ while”循环中。然后,我可以调用VC ++调试器并附加到该进程。然后,我可以使用“全部中断”来停止所有线程。然后,我可以找到卡住的线程的调用堆栈,并可以使用调试器检查顶部框架,并可以检查“ spin”的值,然后将其设置为“ false”。此时,我可以退出此功能和/或设置断点,然后继续运行部分或全部线程。