I have recently been having a problem which essentially makes debugging Go using delve next to impossible. Basically I can't use breakpoints otherwise there is a good chance the debugged code freezes and all I can do is stop the debugger an restart.
To start at the beginning... I have had an intermittent problem debugging Go using GoLand IDE (2019.1) and delve (1.0.0-rc2) for some time. The whole session would freeze - I know that nothing is happening because the debugged process CPU usage is zero, and the fact that there are no messages being written to the log (I have many go-routines most of which are writing occasional log messages). It's as if a breakpoint was hit but the debugger commands (STEP, etc) are not enabled which indicates that the debugger is not at a breakpoint. When this happens I have to hit the GoLand STOP button twice to get the debugger to terminate and then start all over again.
Recently this problem has become far more common. From perhaps a few times a day to almost every debug session. This is annoying but at least it has allowed me to track down what I believe is the underlying problem. It seems that sometimes when a breakpoint is encountered the debugger stops but delve or the IDE does not realise that - so there is no way to continue.
How do I know this? I proved this to myself by setting a breakpoint on a log line (ie, log.Printf). When the breakpoint is on that line (and I know it will be hit) then the debug session freezes. If I ensure there are no breakpoints that will be hit then the program runs absolutely fine including printing the log line. If I set the (one and only) breakpoint on the line after log line the log line is printed and the session freezes.
I think this is a problem with delve. Note that I have loaded the same project into VSCode and the exactly the same thing happens (GoLand and VSCode use the same version of delve), so I don't think GoLand is doing anything wrong. But if someone has another explanation I welcome it.
I have tried a lot of things to track down the cause. I have created a small project in order to demonstrate the problem but it does not occur in a simple project. It appears that I am doing something wrong (in my large project) that causes delve to misbehave but I have no idea what that is.
First, 1.0.0-rc2 seems anvient forn Delve: the current version is 1.2.0
1.0.0-rc2 is so ancient that a similar bug was reported in August 2018 (issue 1318) regarding an headless execution of delve:
dlv debug --headless ...
Adding --log --log-output=rpc can give you additional clues.
dlv debug --headless --listen=:2345 --api-version=2 --log --log-output=rpc ./test.go
Delve itself, in headless mode, will ignore SIGINT.
To stop the headless instance you have to connect to it and then terminate the connection.
To send a SIGINT to the target program you have to start the target program, which you didn't, because to start the target program you have to connect to delve first.
Related
I would like to debug a C++ program in VSCode. The problem is this program is run as part of a large and messy build system that spawns many processes and prepares input for the program. In other words if I run:
./do the_task
It will compile a load of C++, generate some input and eventually - through several layers of Bash, Python and Makefiles - run something like this:
/very/long/path/to/the_task --lots --of --arguments /very/long/path/to/generated_input.xml
I'd like to debug that process using VSCode/GDB, in such a way that I can
Set breakpoints in the_task.cpp
Just click "Start debugging" with the launch.json set to run do the_task
Unfortunately that doesn't work because by default GDB doesn't follow child processes. You can tell it to but then it will halt the parent process so that only a single process runs at a time. That causes everything to get stuck at some point in my case.
Some ideas I've had:
Is there a way to tell GDB to run a script when a new inferior (process) starts, check the executable name and then detach from the child if it doesn't match?
I could create a proxy GDB/MI wrapper that pretends to VSCode that the program has been started (so the connection doesn't time out), and then when we get to running /very/long/path/to/the_task prefix it with gdb --interpreter=mi and forward on all of the cached commands (to set breakpoints etc.) This seems like quite a lot of work and quite hacky so I'm not sure I like it.
Prefix /very/long/path/to/the_task with gdbserver. Then I can connect to it from VSCode. This is definitely the simplest and most obvious solution but the UX sucks - you have to manually start the command, then wait, then click "start debugging". Plus you're inevitably going to run into port reuse annoyances.
3, but write a custom VSCode extension that automatically starts debugging when it detects gdbserver has started. I've done this for Python debugging so it does work but there are some minor annoyances (e.g. if you restart VSCode and it restores a terminal session it doesn't work). Also it's a fair amount of work.
Is there an obvious solution I'm missing?
I was trying to debug a Python program using PyCharm's debugger and each time I resumed execution after hitting a breakpoint my program exited with an obscure error (this particular program is based on Twisted and the error was about not being able to stop an already stopped reactor). The program ran fine within the debugger as long as I didn't stop it with a breakpoint, and it ran fine outside the debugger.
This problem started occurring sometime in the last weeks/month, but in the past I have been able to debug this same program without issue.
It turned out that I just had a function call expression in the PyCharm debug pane that was getting evaluated whenever I hit a breakpoint and that function had a nasty side effect. It was left over from a debugging session several weeks ago related to a shutdown problem (so it kind of makes sense). I pulled a small amount of hair over this, and didn't find anything with google, before I noticed the problem. I hope someone else can learn from my mistake.
I've had several times where I was writing a program using Visual Studio and something, somewhere along the line breaks. Naturally, my first thought is to set a breakpoint early on in the program and then step through the code slowly, line by line until I reach the error.
But often times I find that everything works correctly when slowly stepping through code in the debugger. However, when I just try to run the program without breakpoints something goes wrong.
Why does this happen? Is stepping through the code line by line actually different from just running the program in dubug mode?
(I'm not talking about debug vs release, i'm talking about debug vs line-by-line debugging)
One reason could be that you have timing issues between multiple executing threads that occur differently when the program runs "at full speed" and when you pause a thread in a debugger.
It could be due to a some thread unsafe operations that seem to happen correctly when stepping through the code but not at run time. Compiler optimizations are ruled out because you are sure that you are running a debug build.
Running inside the debugger materially alters the runtime options for eg. heap operations so that errors can be detected and surfaced to the user.
See here.
When a process is run under any debugger, certain heap debug options
are automatically enabled for all heaps in the process.
This is not for sure your issue, but a likely candidate.
So in a C# .NET v4 project in VS2010, I've got a debugging issue. Frequently, if not most of the time, the debugger freezes when you try to use it - typically on exceptions, it's usually OK if you try to manually break.
The only way I've discovered to fix this is to kill the debugged program ([projectname].vshost.exe), which unlocks the IDE and executes all the mouse presses and things that happened in its absence.
The main Windows GUI is not affected. There is minimal CPU load. Waiting does nothing. The output window (full of "Loaded xxx, symbols loaded") is uneventful. I've read about symbol servers deadlocks, or deadlocks in the GUI, but neither of those are the issue here (the symbol servers are disabled).
Anyone have any ideas? This is giving me a big problem, because I can't effectively debug the program.
Unfortunately, this could be any number of things.
Most often, I've had this type of thing happen when the program is caught in an infinite loop... but since yours is breaking on exceptions, maybe you could add some exception handling?
Never did figure this out. Oh well. Limped by with task manager open all summer, but made it through OK.
What is the difference between Start Debugging (F5) and Start without Debugging (CTRL-F5) when the code is compiled in Release mode?
I am seeing that CTRL-F5 is 10x faster than F5 for some C++ code. If I am not wrong, the debugger is attached to the executing process for F5 and it is not for CTRL-F5. Since this is Release mode, the compiled code does not have any debugging information. So, if I do not have any breakpoints, the execution times should be the same across the two, isn't it?!
(Assume that the Release and Debug modes are the typical configurations you get when you create a new Visual C++ project.)
The problem is that Windows drops in a special Debug Heap, if it detects that your program is running under a Debugger. This appears to happen at the OS level, and is independent of any Debug/Release mode settings for your compilation.
You can work around this 'feature' by setting an environment variable: _NO_DEBUG_HEAP=1
This same issue has been driving me nuts for a while; today I found the following, from whence this post is derived:
http://blogs.msdn.com/b/larryosterman/archive/2008/09/03/anatomy-of-a-heisenbug.aspx
"Start without debugging" just tells Windows to launch the app as it would normally run.
"Start with debugging" starts the VS debugger and has it run the app within the debugger.
This really doesn't have much to do with the debug/release build settings.
When you build the default 'debug' configuration of your app, you'll have the following main differences to the release build:
The emitted code won't be optimised, so is easier to debug because it more closely matches your source
The compiler & linker will output a .PDB file containing lots of extra information to help a debugger - the presence or absence of this information makes no difference to the performance of the code, just the ease of debugging.
Conditional macros like ASSERT and VERIFY will be no-ops in a release build but active in a debug build.
Each one of these items is independent and optional! You can turn any or all of them on or off and still run the code under the debugger, you just won't find life so easy.
When you run 'with debugging' things perform differently for several reasons:
The VS debugger is very inefficient at starting, partly because everything in VS is slow - on versions prior to VS2010 every pixel of the screen will be repainted about 30 times as the IDE staggers into debug mode with much flashing and flickering.
Depending on how things are configured, the debugger might spend a lot of time at startup trying to load symbols (i.e. PDB files) for lots and lots of OS components which are part of your process - it might try fetching these files over the web, which can take an age in some circumstances.
A number of activities your application normally does (loading DLLs, starting threads, handling exceptions) all cause the debugger to be alerted. This has the effect both of slowing them down and of making them tend to run sequentially.
IsDebuggerPresent() and OutputDebugString() behave differently depending on whether a debugger is attached.
IsDebuggerPresent() simply returns another value, so your program can react to this value and behave differently on purpose. OutputDebugString() returns much faster when there's no debugger attached, so if it's called lots of times you'll see that the program runs much faster without the debugger.
When running 'with debugging' the debug heap is used, even for release mode. This causes severe slowdowns in code using a lot of malloc/free or new/delete, which can happen in C++ code without you noticing it because libraries/classes tend to hide this memory management stuff from you.