microsoft / vscode-cpptools

Official repository for the Microsoft C/C++ extension for VS Code.
Other
5.53k stars 1.56k forks source link

[MinGW/Cygwin] Send SIGINT automatically when sending breakpoints #2771

Closed HolyBlackCat closed 3 years ago

HolyBlackCat commented 6 years ago

Issue Type: Bug

Pretty much what the title says.

If I add a breakpoint after starting the debugger, it becomes grayed out, with 'unverified breakpoint' tooltip. The application doesn't seem to hit it.

How to reproduce:

Create test.cpp with following contents

#include <iostream>

int main()
{
    unsigned int x = 0;

    while (1)
    {
        std::cout << x++ << '\n';
    }
}

Compile it with g++ -g test.cpp -o out.exe.

In the same directory, create .vscode/launch.json with following contents:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/out.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": true,
            "MIMode": "gdb",
            "miDebuggerPath": "gdb.exe",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "logging": {"traceResponse": true}
        }
    ]
}

Open this directory in VS Code, then open test.cpp. Press DEBUG: (gdb) Launch button.
Try adding a breakpoint on std::cout ... line. Boom, it immediately goes unverified.

Some observations:

If I add a breakpoint before starting an application, it works properly. When application is paused on a such breakpoint, I can add a new breakpoint, and it will work properly as well. But if I press Continue and then add a breakpoint, it doesn't work.

I can't execute any commands in the debug console. If the application is paused on a breakpoint, I get this:

help
-var-create: unable to create variable object
<--   C (evaluate-13): {"command":"evaluate","arguments":{"expression":"help","frameId":1000,"context":"repl"},"type":"request","seq":13}
--> E (output): {"event":"output","body":{"category":"telemetry","output":"VS/Diagnostics/Debugger/Evaluate","data":{"VS.Diagnostics.Debugger.ImplementationName":"Microsoft.MIDebugEngine","VS.Diagnostics.Debugger.EngineVersion":"14.0.51030.1","VS.Diagnostics.Debugger.HostVersion":"14.0.51030.1","VS.Diagnostics.Debugger.AdapterId":"cppdbg","VS.Diagnostics.Debugger.Evaluate.Duration":15.0,"VS.Diagnostics.Debugger.Evaluate.IsError":true}},"seq":95,"type":"event"}
--> R (evaluate-13): {"request_seq":13,"success":true,"command":"evaluate","body":{"result":"-var-create: unable to create variable object","variablesReference":0},"seq":97,"type":"response"}

If the application is already running, I get this:

help
Unable to perform this action because the process is running.
<--   C (evaluate-15): {"command":"evaluate","arguments":{"expression":"help","context":"repl"},"type":"request","seq":15}
--> R (evaluate-15): {"request_seq":15,"success":false,"command":"evaluate","message":"Failed to handle EvaluateRequest","body":{"error":{"id":1105,"format":"Unable to perform this action because the process is running."}},"seq":103,"type":"response"}

My compiler identification is:

>g++ --version
g++ (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

It's the last stable MinGW-w64 build, with default installation settings. Its bin directory is added to PATH.
There are no non-ASCII symbols neither in MinGW path, not in project path. The gdb that comes with MinGW works correctly in this scenario outside of VS Code (e.g. in CodeBlocks).

The contents of the debug console after performing the minimal repro steps described above are

--> E (output): {"event":"output","body":{"category":"telemetry","output":"VS/Diagnostics/Debugger/MIEngine/WindowsRuntime","data":{"VS.Diagnostics.Debugger.MIEngine.WindowsRuntime":"MinGW"}},"seq":2,"type":"event"}

--> E (output): {"event":"output","body":{"category":"telemetry","output":"VS/Diagnostics/Debugger/Launch","data":{"VS.Diagnostics.Debugger.ImplementationName":"Microsoft.MIDebugEngine","VS.Diagnostics.Debugger.EngineVersion":"14.0.51030.1","VS.Diagnostics.Debugger.HostVersion":"14.0.51030.1","VS.Diagnostics.Debugger.AdapterId":"cppdbg","VS.Diagnostics.Debugger.Launch.Duration":307,"VS.Diagnostics.Debugger.Launch.IsCoreDump":false,"VS.Diagnostics.Debugger.VisualizerFileUsed":false,"VS.Diagnostics.Debugger.SourceFileMappings":0}},"seq":4,"type":"event"}

--> R (launch-2): {"request_seq":2,"success":true,"command":"launch","body":{},"seq":6,"type":"response"}

--> E (initialized): {"event":"initialized","body":{},"seq":8,"type":"event"}

<--   C (setFunctionBreakpoints-3): {"command":"setFunctionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":3}

--> R (setFunctionBreakpoints-3): {"request_seq":3,"success":true,"command":"setFunctionBreakpoints","body":{"breakpoints":[]},"seq":11,"type":"response"}

<--   C (setExceptionBreakpoints-4): {"command":"setExceptionBreakpoints","arguments":{"filters":[]},"type":"request","seq":4}

--> R (setExceptionBreakpoints-4): {"request_seq":4,"success":true,"command":"setExceptionBreakpoints","body":{},"seq":14,"type":"response"}

<--   C (configurationDone-5): {"command":"configurationDone","type":"request","seq":5}

--> R (configurationDone-5): {"request_seq":5,"success":true,"command":"configurationDone","body":{},"seq":17,"type":"response"}

<--   C (threads-6): {"command":"threads","type":"request","seq":6}

--> E (output): {"event":"output","body":{"category":"stdout","output":"=thread-group-added,id=\"i1\"\nGNU gdb (GDB) 8.1\nCopyright (C) 2018 Free Software Foundation, Inc.\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.  Type \"show copying\"\nand \"show warranty\" for details.\nThis GDB was configured as \"i686-w64-mingw32\".\nType \"show configuration\" for configuration details.\nFor bug reporting instructions, please see:\n<http://www.gnu.org/software/gdb/bugs/>.\nFind the GDB manual and other documentation resources online at:\n<http://www.gnu.org/software/gdb/documentation/>.\nFor help, type \"help\".\nType \"apropos word\" to search for commands related to \"word\".\nWarning: Debuggee TargetArchitecture not detected, assuming x86_64.\n=cmd-param-changed,param=\"pagination\",value=\"off\"\n"},"seq":21,"type":"event"}

=thread-group-added,id="i1"
GNU gdb (GDB) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Warning: Debuggee TargetArchitecture not detected, assuming x86_64.
=cmd-param-changed,param="pagination",value="off"
--> R (threads-6): {"request_seq":6,"success":true,"command":"threads","body":{"threads":[]},"seq":20,"type":"response"}

--> E (output): {"event":"output","body":{"category":"stdout","output":"[New Thread 6100.0x1678]\n"},"seq":24,"type":"event"}

[New Thread 6100.0x1678]
--> E (output): {"event":"output","body":{"category":"stdout","output":"\n"},"seq":26,"type":"event"}

--> E (output): {"event":"output","body":{"category":"stdout","output":"Breakpoint 1, main () at test.cpp:5\n"},"seq":28,"type":"event"}

Breakpoint 1, main () at test.cpp:5
--> E (output): {"event":"output","body":{"category":"stdout","output":"5\t    unsigned int x = 0;\n"},"seq":30,"type":"event"}

5       unsigned int x = 0;
--> E (thread): {"event":"thread","body":{"reason":"started","threadId":1},"seq":32,"type":"event"}

<--   C (threads-7): {"command":"threads","type":"request","seq":7}

--> R (threads-7): {"request_seq":7,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"Thread #1"}]},"seq":35,"type":"response"}

<--   C (setBreakpoints-8): {"command":"setBreakpoints","arguments":{"source":{"name":"test.cpp","path":"Z:\\Projects\\C++\\imp-re\\bin\\1\\test.cpp"},"lines":[9],"breakpoints":[{"line":9}],"sourceModified":false},"type":"request","seq":8}

--> R (setBreakpoints-8): {"request_seq":8,"success":true,"command":"setBreakpoints","body":{"breakpoints":[{"id":1,"verified":true,"line":9}]},"seq":38,"type":"response"}

--> E (breakpoint): {"event":"breakpoint","body":{"reason":"changed","breakpoint":{"id":1,"verified":false,"message":"Attempting to bind the breakpoint....","line":9}},"seq":40,"type":"event"}

--> E (output): {"event":"output","body":{"category":"stdout","output":"[New Thread 6100.0x18bc]\n"},"seq":42,"type":"event"}

[New Thread 6100.0x18bc]
--> E (output): {"event":"output","body":{"category":"stdout","output":"[Inferior 1 (process 6100) exited with code 030000000472]\n"},"seq":44,"type":"event"}

[Inferior 1 (process 6100) exited with code 030000000472]
--> E (thread): {"event":"thread","body":{"reason":"exited","threadId":1},"seq":46,"type":"event"}

--> E (output): {"event":"output","body":{"category":"console","output":"The program 'Z:\\Projects\\C++\\imp-re\\bin\\1\\out.exe' has exited with code -1 (0xffffffff).\r\n\r\n"},"seq":48,"type":"event"}

The program 'Z:\Projects\C++\imp-re\bin\1\out.exe' has exited with code -1 (0xffffffff).

--> E (exited): {"event":"exited","body":{"exitCode":-1},"seq":50,"type":"event"}

--> E (terminated): {"event":"terminated","body":{},"seq":52,"type":"event"}

--> E (output): {"event":"output","body":{"category":"telemetry","output":"VS/Diagnostics/Debugger/DebugCompleted","data":{"VS.Diagnostics.Debugger.ImplementationName":"Microsoft.MIDebugEngine","VS.Diagnostics.Debugger.EngineVersion":"14.0.51030.1","VS.Diagnostics.Debugger.HostVersion":"14.0.51030.1","VS.Diagnostics.Debugger.AdapterId":"cppdbg","VS.Diagnostics.Debugger.DebugCompleted.BreakCounter":0}},"seq":54,"type":"event"}

<--   C (disconnect-9): {"command":"disconnect","arguments":{"restart":false},"type":"request","seq":9}

--> R (disconnect-9): {"request_seq":9,"success":true,"command":"disconnect","body":{},"seq":57,"type":"response"}

Extension version: 0.20.1 VS Code version: Code - Insiders 1.29.0-insider (bdfe4fd41f6a5fe538197b3cba937230249a563a, 2018-11-04T13:04:20.759Z) OS version: Windows_NT x64 6.1.7601

System Info |Item|Value| |---|---| |CPUs|Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz (4 x 3093)| |GPU Status|2d_canvas: enabled
checker_imaging: disabled_off
flash_3d: enabled
flash_stage3d: enabled
flash_stage3d_baseline: enabled
gpu_compositing: enabled
multiple_raster_threads: enabled_on
native_gpu_memory_buffers: disabled_software
rasterization: enabled
video_decode: enabled
video_encode: enabled
webgl: enabled
webgl2: enabled| |Memory (System)|3.98GB (1.09GB free)| |Process Argv|| |Screen Reader|no| |VM|0%|
rewrking commented 6 years ago

This trips me up all the time, but it seems to be a gcc specific thing. First make sure you compile your debug build with -g & -Og (don't use any other optimizer flag in debug). Next you have to be aware of this limitation:

https://code.visualstudio.com/docs/languages/cpp#_known-limitations

GDB on Cygwin and MinGW cannot break a running process. To set a breakpoint when the application is running (not stopped under the debugger), or to pause the application being debugged, press Ctrl-C in the application's terminal.

So for instance if you're writing a game and have a game loop that updates/draws every frame, you have to either start debugging with existing breakpoints (and set new ones during those breaks) or hit Ctrl+C in the external console/windows command prompt after you've set new breakpoints on the fly.

HolyBlackCat commented 6 years ago

@andrew-r-king I'm already using -g with no other flags, as the issue says.

Thanks for the Ctrl+C trick! It looks like a reasonable workaround.

But if sending SIGINT manually works, couldn't VS code send it automatically when I place breakpoint while a program is running?

Also, in CodeBlocks placing a breakpoint somehow works as expected. Maybe they're doing just that?

pieandcakes commented 6 years ago

@HolyBlackCat We have tried to work around this on Windows and haven't found a good way to send SIGINT to MinGW (or CYGWIN). The only way to set the breakpoint is what @andrew-r-king has mentioned, to send SIGINT yourself and stop and then set breakpoints OR set a breakpoint ahead of time (or use stopAtEntry) and set your other breakpoints. If we could send SIGINT to the debugger during this process, it would be easier to deal with.

I don't know how CodeBlocks is doing it.

HolyBlackCat commented 6 years ago

@pieandcakes I've rummaged in CB sources a bit, and found a part where they're sending the interrupt.

Here it is, function DebuggerGDB::DoBreak: http://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/debuggergdb/debuggergdb.cpp

Sunggekun commented 5 years ago

Code::Block break by using DebugBreakProcess() to send breakpoint exception to debuggee on Windows.

github-actions[bot] commented 3 years ago

This issue has been closed automatically because it has not had recent activity.

justanotheranonymoususer commented 3 years ago

@pieandcakes is it possible to reopen this important issue? It's essential to be able to debug with GDB on Windows. Without it, breakpoints and pausing don't work, and debugging non-console apps is not possible.

github-actions[bot] commented 3 years ago

This issue has been closed automatically because it has not had recent activity.

dustinlacewell commented 1 year ago

How is it possible this was never resolved?!