15

调试时,有时您需要附加一个已经在运行的进程,而不是仅仅在调试器中启动应用程序。

我自己通常会调用 Sleep() 或 MessageBox,以便更容易附加调试器。我担心其中一些可能最终会提交到源代码控制。

为了避免这种情况,最好的办法是什么,同时仍然延迟足够的时间,以便您可以将调试器附加到正在运行的进程?

用 an 保护睡眠或消息框#ifdef _DEBUG是一种方法,但我想知道是否有更好的方法。

使用睡眠,您还会遇到无法及时连接的问题。使用 MessageBox,您可能会遇到问题,您可能正在远程调试,或者调试没有可见 GUI 的进程(例如在 Vista 上作为服务运行)

4

8 回答 8

17

我有时使用的另一个变体是

while( !::IsDebuggerPresent() )
    ::Sleep( 100 ); // to avoid 100% CPU load

它应该静静地等待,直到您将调试器附加到进程。

于 2016-01-26T15:51:07.020 回答
11

您可以使用 DebugBreak,检查以下链接:

http://www.epsilon-delta.net/articles/vc6_debug.html#break-with-debugbreak

http://blogs.msdn.com/calvin_hsia/archive/2006/08/25/724572.aspx

于 2009-03-19T18:43:04.560 回答
9

要在特定点附加调试器,您有几个选项:

最简单的就是调用DebugBreak,它几乎等同于__asm int 3,但也适用于其他架构(如果我没记错的话,x64 的 MSVC 不允许内联汇编)。这将打开即时调试器窗口,您将能够从已注册的调试器(即 Visual Studio)中进行选择以附加到进程。

或者,您可以引入对 的调用Sleep,让您有机会附加调试器。您应该使用#ifdef _DEBUG它,以确保您实际上并未包含此代码。

一个问题:为什么不能从 IDE 运行代码?它是服务还是加载 IIS 的 DLL 或类似的?

在这种情况下,您可以查看ImageFileExecutionOptions注册表项,它允许您在进程启动时附加调试器。

如果为此使用 cdb,则可以将其配置为 WinDbg 实例的服务器或客户端,并以这种方式进行调试。过去我通过使用 WinDbg 作为内核调试器并使用 ImageFileExecutionOptions 从ntsd -d命名进程开始来完成此操作。这会导致 WinDbg 进入用户模式。这有时是一种有用的技术。

于 2009-03-19T18:54:53.720 回答
7

Freddy 和 Reoa 有正确的解决方案。但我想添加一个不使用 MessageBox 的原因。

显示 MessageBox 只会部分停止您的应用程序。因为您正在显示 UI,所以消息泵仍在程序中的至少一个线程上运行。因此,如果您的代码执行以下任何操作。

  1. 通过 Windows 消息进行通信
  2. 有非平凡的用户界面
  3. 是多线程的

您实际上将在一种状态下请求调试器,但以完全不同的状态附加到您的程序。这可能会导致令人困惑的情况和错误。

我们最近对我们的代码库进行了更改,不再显示 MessageBox 以方便中断,正是出于这个原因。对于非平凡的应用程序,它会产生非常糟糕的行为。

于 2009-03-19T18:52:57.003 回答
2

必须在“恰到好处”处附加是一种痛苦……一种选择是将显式 DebugBreak() 语句添加到代码中以强制解决问题,并用它们来保护它们#ifdef _DEBUG是个好主意。我们使用一个可以调用 DebugBreak() 的 ASSERT 宏,所以你可以只写 ASSERT(false)

另一个需要考虑的选项是使用“图像文件执行选项”来自动启动调试器。请参阅此博客MSDN文档。

于 2009-03-19T18:44:43.217 回答
1

抬头:

DebugBreak , __debugbreak 和朋友们

或者

静态无效 timeToChase() { __asm { int 3; }; }

于 2009-03-19T18:43:21.097 回答
1
__asm int 3 

这个硬断点将打开调试对话框,让您附加到进程。将其包装在 #ifdef _DEBUG 中,您只会在调试版本中使用它。

于 2009-03-19T18:44:55.523 回答
1

如果 __debugbreak() 或 DebugBreak() 对你有用,那么我认为这可能是最好的方法。

但是,我遇到了一些情况,由于未知原因,__debugbreak() 只是立即终止程序,而不是等待调试器连接。我尝试了各种方法来解决这个问题(注册表黑客等),但似乎没有任何效果。(在这种情况下,我尝试调试的进程不是直接从命令行启动,而是由 Java 程序启动,这可能是相关的。)

无论如何,在那种情况下,我使用了这种方法,似乎效果很好:

void waitForDebuggerToConnect() {
    #ifdef _DEBUG
    static volatile bool spin = true;
    while (spin)
    {}
    #endif
}

调用此函数后,我的程序将无限期地挂在“while”循环中。然后我可以调用 VC++ 调试器并附加到该进程。然后我可以使用“全部中断”来停止所有线程。然后我可以找到卡住的线程的调用堆栈,并可以使用调试器检查顶部帧,并可以检查'spin'的值,然后将其设置为'false'。此时,我可以退出该函数和/或设置断点,然后恢复部分或所有线程运行。

于 2020-07-09T19:17:48.343 回答