【问题标题】:In GDB on MinGW, how do I make Ctrl-C stop the program?在 MinGW 上的 GDB 中,如何让 Ctrl-C 停止程序?
【发布时间】:2009-04-02 18:46:21
【问题描述】:

我在 Windows 上,在 MinGW 下构建的可执行文件上运行 GDB。该程序有一个无限循环。我想通过点击 Ctrl + C 来找到它。当我这样做时,程序和 GDB 都会退出。关于这个主题的所有帮助似乎都假设我使用的是 Linux。

【问题讨论】:

    标签: gdb mingw


    【解决方案1】:

    这是因为 GDB 没有正确处理 GUI(非控制台)程序的 Ctrl + C 事件。

    您可以在 Workaround for GDB Ctrl-C Interrupt 中找到解决方法。


    更新:鉴于 mingw.org 域已过期,以下是从 Web 存档中抢救出来的代码:

    如果您发现自己试图用 Ctrl-C 中断 GDB 正在调试的程序并且失败了,那么这个小程序将允许您从另一个会话发出中断。只需通过正在调试的进程的 Windows pid 运行它,GDB 就会重新获得控制权。 [编译,使用gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c]

    /* BEGIN debugbreak.c */
    
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0501
    #endif
    
    #if _WIN32_WINNT < 0x0501
    #error Must target Windows NT 5.0.1 or later for DebugBreakProcess
    #endif
    
    #include <Windows.h>
    #include <stddef.h>
    #include <stdlib.h>
    
    /* Compile with this line:
    
        gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c
    
    */
    
    static char errbuffer[256];
    
    static const char *geterrstr(DWORD errcode)
    {
        size_t skip = 0;
        DWORD chars;
        chars = FormatMessage(
            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
        errbuffer[sizeof(errbuffer)-1] = 0;
        if (chars) {
            while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n') {
                errbuffer[--chars] = 0;
            }
        }
        if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
        if (chars >= 2 && errbuffer[0] == '%' && errbuffer[1] >= '0'
            && errbuffer[1] <= '9')
        {
            skip = 2;
            while (chars > skip && errbuffer[skip] == ' ') ++skip;
            if (chars >= skip+2 && errbuffer[skip] == 'i'
                && errbuffer[skip+1] == 's')
            {
                skip += 2;
                while (chars > skip && errbuffer[skip] == ' ') ++skip;
            }
        }
        if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <= 'Z') {
            errbuffer[skip] += 'a' - 'A';
        }
        return errbuffer+skip;
    }
    
    int main(int argc, char *argv[])
    {
        HANDLE proc;
        unsigned proc_id = 0;
        BOOL break_result;
    
        if (argc != 2) {
            printf("Usage: debugbreak process_id_number\n");
            return 1;
        }
        proc_id = (unsigned) strtol(argv[1], NULL, 0);
        if (proc_id == 0) {
            printf("Invalid process id %u\n", proc_id);
            return 1;
        }
        proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
        if (proc == NULL) {
            DWORD lastError = GetLastError();
            printf("Failed to open process %u\n", proc_id);
            printf("Error code is %lu (%s)\n", (unsigned long)lastError,
                geterrstr(lastError));
            return 1;
        }
        break_result = DebugBreakProcess(proc);
        if (!break_result) {
            DWORD lastError = GetLastError();
            printf("Failed to debug break process %u\n", proc_id);
            printf("Error code is %lu (%s)\n", (unsigned long)lastError,
                geterrstr(lastError));
            CloseHandle(proc);
            return 1;
        }
        printf("DebugBreak sent successfully to process id %u\n", proc_id);
        CloseHandle(proc);
        return 0;
    }
    
    /* END debugbreak.c */
    

    感谢 Kyle McKay 将代码发布到 cygwin 邮件列表 http://cygwin.com/ml/cygwin/2006-06/msg00321.html

    【讨论】:

    • 太糟糕了,您只能使用解决方法来调试 Windows 程序。至于我,我正在调试一个 Android 程序 :(
    • cmd.exe 那样切换到正确的控制台确实有帮助:我按Ctrl+C,GDB 的行为与它在Linux 上的行为相同。所以链接到这里的解决方法没有那么有用。
    • 就我而言,在 Windows 10 下使用 mingw gdb 测试程序,从 powershell 切换到 cmd.exe 并没有帮助。建议的解决方法确实如此。
    【解决方案2】:

    您使用的是哪个“外壳”?如果您使用 MSYS “rxvt” shell,则行为与您描述的差不多。 Ctrl-C 仅在您从正常的 Windows 命令提示符下运行时才有效。

    【讨论】:

    • 这是有用的信息。我在 Windows 命令提示符下,但它似乎不起作用,但我会再试一次。
    • 你也可以试试“Console2”。这应该接近 Windows 命令提示符,但它更漂亮。我一直使用 gdb,从来没有任何问题。 sourceforge.net/projects/console
    【解决方案3】:

    我也遇到了同样的问题。

    wiki 的解决方法是使用被调试进程的 pid 运行 debugbreak,但 ps 不显示此 pid,仅显示 gdb 的 pid。或许还有其他途径获得。

    但有更简单的解决方法。只需正常启动程序(不在 gdb 中),从 ps 检查 pid 并使用此 pid 作为第二个参数启动 gdb。 附加 gdb 后,进程停止,我可以打印回溯。

    【讨论】:

    • 谢谢。前段时间我遇到了这个问题:点击 ^C 并且调试器停止,但它停止在与主程序不同的线程中。如果我再做信息线程,它会告诉主程序的线程号。然后我切换到那个线程,我可以用bt 来显示堆栈。我想这对于真正了解 GDB 的人来说是完全显而易见的。
    【解决方案4】:

    我遇到了同样的问题。为我解决的问题是将 gdb 与 cmd.exe 一起使用并在 gdb 中设置以下选项。

    set new-console on
    

    现在我可以使用 Ctrl + c 来中断 gui 和控制台程序。

    【讨论】:

      【解决方案5】:

      这是一个每次都有效的解决方案:

      当 GDB 启动时使用这个正则表达式来捕获下级进程 id:

      "\[New Thread (\d+)\."
      

      然后使用:

      hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, PID);
      DebugBreakProcess(hProcess);
      CloseHandle(hProcess);
      

      查看以下 GDB 初始化脚本,它是在 Windows 7 及更高版本上与 MinGW 一起使用所必需的:

      # =====================================
      #  GDB preload initialization commands
      # =====================================
      
      # Set Unicode Charset
      #set target-charset UCS-2
      #set host-charset UCS-2
      #set charset UCS-2
      #set target-wide-charset UCS-2
      
      # Set UTF-8 Charset
      set target-charset UTF-8
      set host-charset UTF-8
      set charset UTF-8
      set target-wide-charset UTF-8
      
      # Request async target mode
      set target-async 1
      
      # Do not complain about pending breakpoints
      set breakpoint pending on
      
      # Enable All-Stop for all Threads
      set non-stop off
      
      # Do not ask for confirmations
      set confirm off
      
      # Do not create new console for output/logging
      set new-console off
      
      # Turn-off paggination to allow integration with IDE
      set pagination off
      
      # Call Stack files (and anywhere else) should be absolute path
      set filename-display absolute
      
      # Enable Pretty Print in GDB Panel
      set print pretty on
      
      # Enable notification of completion for asynchronous execution commands.
      set exec-done-display on
      
      # Show Addresses in objects, required for integration with IDE
      set print address on
      
      # Enable Pretty Print for Arrays
      set print array on
      
      # Flatten objects, required for integration with IDE
      set print object off
      
      # Include static members, required for integration with IDE
      set print static-members on
      
      # Show demangled vtable, required for integration with IDE
      set print vtbl off
      set print demangle on
      set demangle-style gnu-v3
      
      # Print full eight-bit characters, required for integration with IDE
      set print sevenbit-strings off
      
      # Set path for obj files
      path $(TARGET_ROOT)/obj
      
      # Load gdb scripts for STL (string, vector, map, etc.)
      source $(PATH_SDK_DEBUGGER)/stl-views-1.0.3.gdb
      
      # List of source code files
      dir $(PATH_SDK_COMMON)
      dir $(PATH_SDK_FRAMEWORKS)
      dir $(PATH_SDK_INCLUDES)
      dir $(PROJECT_PATHS.NATIVE_COMMON)
      
      # Load the binary
      file $(TARGET_OUTPUT)
      

      【讨论】:

        【解决方案6】:

        作为Matthew Talbert pointed out,当在 MSYS/Cygwin 中使用使用本机 MinGW 工具链构建的 GDB 时会发生这种情况。使用 winpty 启动 GDB 就像一个魅力,因为它是专门为此而设计的工具。它也适用于cdb.exe

        【讨论】:

          【解决方案7】:

          如果您从 https://www.msys2.org/ 安装最新的 MinGW-x64,那么 Ctrl-C 就可以了。

          c:\test>gdb a.exe
          GNU gdb (GDB) 7.11.1
          . . .
          Reading symbols from a.exe...done.
          (gdb) r
          Starting program: c:\test\a.exe
          <Ctrl>-<C>
          Thread 5 received signal SIGINT, Interrupt.
          [Switching to Thread 17312.0x5614]
          0x00007ff97e75d7e3 in TlsGetValue () from C:\WINDOWS\System32\KernelBase.dll
          (gdb)
          

          如果你在Cygwin,你需要告诉gdbhandle SIGINT

          (gdb) handle SIGINT
          SIGINT is used by the debugger.
          Are you sure you want to change it? (y or n) y
          Signal        Stop      Print   Pass to program Description
          SIGINT        Yes       Yes     No              Interrupt
          (gdb)
          

          【讨论】:

            【解决方案8】:

            要找到无限循环,您可以尝试逐步执行,直到找到无限重复的序列。

            我不确定,但我认为 Ctrl-C 应该只停止执行,而不是 gdb 本身...

            我认为有一个“handle”命令可以用来控制中断信号的处理方式。

            【讨论】:

            • 我知道。我希望不必这样做。
            • 你在这两个方面都是对的,但它似乎不适用于 Windows DOS-box。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-29
            • 1970-01-01
            • 2014-07-10
            • 2011-08-19
            • 1970-01-01
            相关资源
            最近更新 更多