Marus / cortex-debug

Visual Studio Code extension for enhancing debug capabilities for Cortex-M Microcontrollers
MIT License
984 stars 238 forks source link

Watch variables disappear in VSCode when debugging an STM32 project #406

Closed classbproject closed 2 years ago

classbproject commented 3 years ago

I've been trying to debug an STM32 project in VSCode. I'm able to start the debugger and add variables to the watch list. However, the moment I run the code, the watch variables disappear. Is there a way to view them in real-time as the code is running? Here is a short video of what happens.

RisinT96 commented 3 years ago

AFAIK no, standard GDB doesn't allow executing commands while the target is not halted (meaning no memory reads).

I've seen VisualGDB do something similar to what you want but I guess they are using some custom debug server.

Correct me if I'm wrong :)

Marus commented 3 years ago

As @RisinT96 said - standard watch variables are only available while the target is halted - as there are limited commands that you can execute while the core is active.

That said I recently read some blog posts from the VisualGDB developer about that feature- and I am investigating if something similar would be feasible or not. I don’t have any ETA on this feature mind you.

Another option that is currently available (assuming you’re targeting an m3 or above device with the feature), that I tend to use quite a bit, is SWO output. This of course requires modifications to the target program, but SWO tends to have much less overhead than say “printf” via regular serial or semi-hosting. I tend to use SWO outputting binary data over formatted text. The extension has a fair amount of ways to process and graph this data.

classbproject commented 3 years ago

Thanks! How do CubeIDE/CubeMonitor or Keil uVision do this then?

Marus commented 3 years ago

Well, I don't know their internals but I'd expect it's a similar approach to what VisualGDB uses, and what I'm looking at for feasibility of implementing within cortex-debug.

As a general rule you can actually read memory while the processor is running; but what you can't do is issue a command like "what is the value of variable x" - as if the processor isn't stopped GDB has no way to determine what x actually means as it doesn't have a current context.

The general approach that VisualGDB uses, and what I'm looking at, is that it parses the binary using objdump to find global variables which you can then watch live (what refresh rate would be feasible I don't know yet). You would not be able to watch things like local variables though, as they don't have a fixed place in memory and without a frame of reference to use (which requires the processor core to be stopped) it is impossible to determine where in memory they actually are at a given moment.

RisinT96 commented 3 years ago

Hmm that's very interesting.

You could also halt, get the type information+address of the variable and then continue the run, that way you can track even local variables.

That's the approach I've seen in VisualGDB, you can add live watches when the device is halted and it will continue tracking them even when the software goes out of scope (obviously the data is now invalid but it keeps tracking the same address).

It would be possible to add those to a separate "Live Watch" window.

haneefdm commented 3 years ago

Yeah, it can only work on global/static variables because we can extract the address. Watch variables can also contain expressions. But we will also need type info and how to decode that which we currently don't do. Not sure about local vars though.

Worth an investigation.

RisinT96 commented 3 years ago

Yeah, it can only work on global/static variables because we can extract the address. Watch variables can also contain expressions. But we will also need type info and how to decode that which we currently don't do. Not sure about local vars though.

Worth an investigation.

I've recently written some code that deals with parsing dwarf information to extract type information of variables, and then convert raw bytes into typed data (using the type information). But it's hardwired for DWARF 4 and I cannot promise compatibility with other versions.

I could try to help out if I have any spare time.

Marus commented 3 years ago

Well, in my mind local variables don’t really make sense for a live watch (even if you can get them started when halted), because as soon as you’ve returned from a function then it is no longer valid - you’re just going to be watching an arbitrary address from the stack somewhere.

But it is something I am looking into for global variables (and perhaps heap allocated things might make sense if you’re using dynamic memory allocation).

Marus commented 3 years ago

@RisinT96 - for the first pass I’ll likely be tapping into objdump for getting symbol information for the global variables - as we already make use of that for certain other functionality. If that doesn’t seem to be sufficient then might ask to look into what you’ve done for DWARF parsing.

haneefdm commented 3 years ago

Visual GDB does a live watch in a brute-force way. They periodically stop/update/continue the debugger, so it is pretty intrusive -- hundreds of milliseconds. Even if the GUI is optimized to only update the Watch variables it will be pretty expensive in VSCode.

In Visual GDB, they can choose not to update anything except the live variables -- we can try doing that, but may not be pretty -- but it will still be several milliseconds. So, Live Watch is not exactly non-intrusive. They have a Globals mode where they claim is faster and less intrusive. Likely using SWD snooping.

A cooperative debug method may be a substitute or even better. That is using RTT (or SWO) where you control the frequency of the updates. Of course, it requires FW changes which is less appetizing. But, we have printing and plotting facilities in Cortex-Debug -- which can be enhanced if needed.

haneefdm commented 2 years ago

The title is not really correct and this has morphed into live variables which I am looking into.

Also a dup of #512, closing this one.