vadimcn / codelldb

A native debugger extension for VSCode based on LLDB
https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb
MIT License
2.55k stars 246 forks source link

"Go to source location" from the variables view #861

Closed vogelsgesang closed 1 year ago

vogelsgesang commented 1 year ago

This is mostly a "request for comments/ideas" and an open-ended discussion. Afaict, getting my preferred solution will require collaboration across DAP, VSCode and you, the author of this extension. I am happy to create a Pull Request to integrate my preferred solution with vscode-lldb, but want to first get your opinion whether you would like to have such functionality in vscode-lldb (since otherwise, my time investment would be a waste).

The problem / use case

C++ and Rust both support function pointers. The current debugging experience for function pointers is acceptable but not ideal. E.g., a function pointer is currently rendered as shown in the screenshot below

Screenshot 2023-02-10 at 15 42 24

Futhermore, C++ and Rust have types which allow "introspection" at runtime: In C++, there is std::source_location, std::stacktrace. In Rust, there is std::backtrace. Currently, libc++std::source_location (see libc++ implementation) is displayed as

_M_file_name: "/path/to/my/file.cpp"
const char* _M_function_name;
_M_line: 353
_M_column: 28

I currently have to manually navigate to the location in that file which is cumbersome if I am inspecting many function pointers or a complete std::backtrace.

My preferred solution

As a user of VSCode, I would like to have some "Go to source location" hyper link directly next to my function pointers/std::source_location variables inside the variable view. The description of the variable already states at func-ptr-example.cpp:3:14, so the debugger clearly has all the required information available.

From a user experience point of view, I could imagine a new button similar to the existing "View Binary Data" (see screenshot). Clicking this "View source code reference" button should take me directly to the correct source location in my editor.

Screenshot 2023-02-10 at 15 49 14

Implementation thoughts

This would require the addition of a sourceReference to the debug-adapter protocol (similar to the existing memoryReference). I posted a corresponding extension proposal for DAP in https://github.com/microsoft/debug-adapter-protocol/issues/372

For function pointers, I guess vscode-lldb already have all the information available from lldb, so you could provide this sourceReference to the VSCode UI through DAP.

For std::source_location and std::backtrace, I would probably need to have a pretty printer in lldb itself. I posted in https://discourse.llvm.org/t/rfc-extending-formatters-with-a-source-code-reference/68375, to ask for the opinion of LLDB developers

vadimcn commented 1 year ago

If Microsoft accepts this feature into DAP and VSCode, I'm open to implementing it.
Frankly, this seems too specific to your project, I wouldn't expect the majority of VSCode users to ever need this. If I were you, I would instead look into creating a type summary for these types, which would present locations is a format ready for copy-pasting into VSCode command bar.

vogelsgesang commented 1 year ago

Thanks for this idea! Happy to explore other solutions which are less effort 🙂

Frankly, this seems too specific to your project, I wouldn't expect the majority of VSCode users to ever need this

You mean that having to follow function pointers/std::source_location variables is too specific? Or some other part of my proposal?

Note that Chrome also has this functionality in its web-development tools:

Screenshot 2023-02-12 at 18 44 31

So it seems that the Chrome/JavaScript/TypeScript community also considered this a useful functionality

vogelsgesang commented 1 year ago

Hm... interestingly, VS Code's debugger also shows this source code location when debugging JavaScript. But for them, it is highlighted as a link which I can directly click and navigate to.

Screenshot 2023-02-12 at 19 03 22

The difference is that vscode-lldb provides a relative path (at func-ptr-example.cpp:3:14) while the JavaScript debugger provides an absolute path (see this regexp to see which patterns are recognized as file links). Are you aware of some way to configure vscode-lldb/lldb to use absolute paths in its summary texts? Would you be willing to change vscode-lldb to always provide absolute, i.e. clickable paths?

vadimcn commented 1 year ago

You mean that having to follow function pointers/std::source_location variables is too specific?

Yes, that. In all my career I've never felt I need a fast way to jump from a function pointer to a source file. Not sure what motivated JavaScript folks to implement that. Perhaps this is because file system and network calls in nodejs involve lots of callbacks?

Hm... interestingly, VS Code's debugger also shows this source code location when debugging JavaScript. But for them, it is highlighted as a link which I can directly click and navigate to.

Cool, I didn't know about this feature. But VSCode hyperlinks file paths in embedded terminal and in other places, so why not here, right?

Are you aware of some way to configure vscode-lldb/lldb to use absolute paths in its summary texts?

As I said, I would look into creating a custom type summary for these types.

Would you be willing to change vscode-lldb to always provide absolute, i.e. clickable paths?

Depends on the size of the patch... Generally I prefer to tweak upstream lldb as little as possible. It is already a headache to have to rebase Rust-related changes in lldb with each release. The bar for merging changes upstream is higher than what you'd do for yourself only. For example, you'd need to make sure it works on Windows too. Also in scenarios where the build system build system rewrites source file paths in debug info for hermetic builds.

vogelsgesang commented 1 year ago

Not sure what motivated JavaScript folks to implement that. Perhaps this is because file system and network calls in nodejs involve lots of callbacks?

My motivation/use case is also "callbacks for asynchronous processing in boost::asio/C++20 coroutines". In case you are interested, some more context towards the end of this message.

And now that I look at the screenshot below again... I don't think that fully-qualified names would indeed solve my problem 🙁 Note how the "at " part is completely truncated. So even if I could get LLDB to emit absolute paths, the link wouldn't be visible...

As I said, I would look into creating a custom type summary for these types.

You mean a custom type summary for all function pointers? Not sure if that works. The formatter for function pointers seems to be hardcoded in https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp#L1389

Either way, I think I would rather just try to convince LLDB to accept a patch introducing the symbols.print-absolute-paths setting (or similar) which allows me to configure whether the printed file names are fully-qualified or relative paths.

Would you be willing to change vscode-lldb to always provide absolute, i.e. clickable paths?

Depends on the size of the patch... Generally I prefer to tweak upstream lldb as little as possible.

Not sure if I can follow. My understanding would be that if I tweak upstream lldb and introduce the symbols.print-absolute-paths setting in upstream LLVM, the patch to vscode-lldb would be a rather maintainable one-line-change which updates that setting...

The bar for merging changes upstream is higher than what you'd do for yourself only. For example, you'd need to make sure it works on Windows too. Also in scenarios where the build system build system rewrites source file paths in debug info for hermetic builds.

Yes, I became aware of that. I still didn't get https://reviews.llvm.org/D132735 to work on OSX... But at the same time, that higher bar is good. I need this to work on Window, OSX & Linux anyway, as the project I am working on ships on all 3 platforms and uses a hermetic Bazel build


More context on debugging of C++20 coroutines:

In the screenshot below, you can see vscode-lldb showing myAsyncFunction coroutine type (pretty similar to the proposed std::lazy). I am using LLDB-17 as an alternate backend here because it already contains my std::coroutine_handle pretty printer (https://github.com/llvm/llvm-project/commit/91389000abe8ef5d06d98cbbefd3fa03ac7e4480, https://github.com/llvm/llvm-project/commit/01f4c305fae9ff2f165ce0f635a90f8e2292308c).

The __promise variable is a compiler generated variable which gets created by the C++ compiler, and contains the context of the current coroutine. By following the chain of continuation members inside the promise, I can see my complete "logical callstack". The resume function pointers give me my asynchronous call stack. To understand my call-stack, I need to look at the functions corresponding to those pointers

This is essentially the same method as proposed by LLVM authors in "Debugging C++ coroutines", but using a built-in pretty printer instead of a lot of manual pointer-casts.

Screenshot 2023-02-10 at 12 52 03
vadimcn commented 1 year ago

You mean a custom type summary for all function pointers? Not sure if that works. The formatter for function pointers seems to be hardcoded i

Are you sure there is no way to override that? Well, if so, maybe that's the bug that needs fixing...

Not sure if I can follow. My understanding would be that if I tweak upstream lldb and introduce the symbols.print-absolute-paths setting in upstream LLVM, the patch to vscode-lldb would be a rather maintainable one-line-change which updates that setting...

I was under impression that you are proposing to upstream this patch to my private fork of llvm. If you upstream it to llvm-project, then there's no problem of course. :+1:

Speaking of DAP/VSCode changes you propose, I personally would prefer a more generic extension, that would allow attaching "advanced visualizations" to values in other contexts as well. For example, one could imagine image visualizer attached to variables containing bitmaps, spacial viewers for matrices and vectors, etc. Visual Studio proper supports something like this.

vogelsgesang commented 1 year ago

Are you sure there is no way to override that?

No, I am not sure. I still need to follow up on that.

Speaking of DAP/VSCode changes you propose, I personally would prefer a more generic extension, that would allow attaching "advanced visualizations" to values in other contexts as well. For example, one could imagine image visualizer attached to variables containing bitmaps, spacial viewers for matrices and vectors, etc. Visual Studio proper supports something like this.

yes, I see the highlevel use case for attaching advanced visualizers to values would be great, too! That would allow to add, e.g., a validation status ("is this variable violating any of its invariants?"), image viewers for objects treated by image libraries (OpenCV, OpenGL, ...), or visualizations of matrices/vectors for linear algebra libraries such as Eigen.

I am not sure how those use cases overlap with the "go to source location" use case which I have in mind, though...

How would you imagine such custom visualizers to work? Would you want to have a "Visualize/Inspect/..." button next to your values inside the value-view? What would happen if I click this button? What would be the user experience? Would it open a popup/popover? Would it spawn a completely separate program which might potentially display its own UI? Would it open a new tab inside VS code, which you can let point back to some content provided by your own extension?

vogelsgesang commented 1 year ago

attaching "advanced visualizations" to values in other contexts as well

attaching custom "actions" to values inside the debugger view would be quite useful, too, by the way...

I am using rr very extensively, and quite frequently my workflow is:

  1. run the recorded program until it crashes due to some variable having an unexpected value
  2. setting an "write" breakpoint on that variable
  3. hitting reverse-continue -> now I am at the point where the variable was set to the bogus value
  4. unsetting the "write" breakpoint again

Having a "right-click -> reverse-continue until last write" inside the variable view would be very useful to combine steps 2-4 into a single one

vadimcn commented 1 year ago

I am not sure how those use cases overlap with the "go to source location" use case which I have in mind, though...

In that it could be implemented as such a visualizer.

puremourning commented 1 year ago

The main advantage of it being in DAP and supported by the DA is that should be client agnostic. The visualisers are client-specific and format strings require work from all users. Admittedly this is a pretty niche feature (go to target of fn ptr) but more broadly the protocol will likely adopt a mechanism to attach a source location to a Variable which is more widely useful I think.

vogelsgesang commented 2 months ago

Support for code locations was merged upstream in the debug adapter protocol and in VS-Code recently and will be included in the next VS-Code release.

For lldb-dap, there is an implementation of it in https://github.com/llvm/llvm-project/pull/104589. Might be interesting to also adopt for this extension