Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger: Show local variables as values, they are currently reported as memory addresses #7007

Open
David-Else opened this issue May 9, 2023 · 7 comments
Labels
A-debug-adapter Area: Debug adapter client C-enhancement Category: Improvements

Comments

@David-Else
Copy link
Contributor

I understand that the debugger is experimental, but surely it is useless at the moment if we can't see the value of the variables?

Everything else seems to work, this one fix would make the debugger very useful. Why has it been left in this state, are the memory addresses useful to some people?

mem

@David-Else David-Else added the C-enhancement Category: Improvements label May 9, 2023
@kirawi kirawi added the A-debug-adapter Area: Debug adapter client label May 10, 2023
@HealsCodes
Copy link

It looks like this is down to using lldb-vscode / codelldb without enabling the rust pretty printer flags.
If you debug rust on the command-line there is a wrapper called rust-lldb which executes a number of pre-launch commands to setup rust pretty printing for variables. I don't know how to pass XXX to lldb-vscode but it has support to run setup commands as well.

These would be the commands in question:

(lldb) command script import "/Users/USER/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/etc/lldb_lookup.py"
(lldb) command source -s 0 '/Users/USER/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/etc/lldb_commands'

"lldb_commands" executing the following:

(lldb) type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
(lldb) type summary add -F lldb_lookup.summary_lookup  -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
(lldb) type category enable Rust

And here's a comparison - stock lldb vars:

lldb without rust pretty printing

And lldb after executing the two setup commands:

lldb with rust pretty printing

@quantonganh
Copy link
Contributor

It looks like this is down to using lldb-vscode / codelldb without enabling the rust pretty printer flags.
If you debug rust on the command-line there is a wrapper called rust-lldb which executes a number of pre-launch commands to setup rust pretty printing for variables. I don't know how to pass XXX to lldb-vscode but it has support to run setup commands as well.

We can ask lldb-vscode to execute these commands by using initCommands.

Add the following to ~/.config/helix/languages.toml:

[[language]]
name = "rust"

[language.debugger]
name = "lldb-vscode"
transport = "stdio"
command = "lldb-vscode"

[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { program = "{0}", initCommands = [ "command script import /opt/homebrew/Cellar/rust/1.71.0/lib/rustlib/etc/lldb_lookup.py", "command source -s 0 /opt/homebrew/Cellar/rust/1.71.0/lib/rustlib/etc/lldb_commands" ] }

and voila:

Screen Shot 2023-08-11 at 08 12 21

@HealsCodes
Copy link

HealsCodes commented Aug 11, 2023

We can ask lldb-vscode to execute these commands by using initCommands.

Add the following to ~/.config/helix/languages.toml:

[[language]]
name = "rust"

[language.debugger]
name = "lldb-vscode"
transport = "stdio"
command = "lldb-vscode"

[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { program = "{0}", initCommands = [ "command script import /opt/homebrew/Cellar/rust/1.71.0/lib/rustlib/etc/lldb_lookup.py", "command source -s 0 /opt/homebrew/Cellar/rust/1.71.0/lib/rustlib/etc/lldb_commands" ] }

Nice start but won't work for the majority of people and will break even on your system anytime soon as you're specifying a versioned path into a homebrew install on AppleSilicon.

Most people will likely install via rust-up (which goes to $HOME/.rustup) and even if they use homebrew the path is different between AppleSilicon (/opt/homebrew) and Intel (/usr/local/homebrew).

The path you want to pass to lldb-vscode is $(rustc --print sysroot)/lib/rustlib/etc/lldb_lookup.py which expands to the correct lldb_lookup.py for your active rustc regardless of which platform or version you're using.

Just leaves the problem that AFAIK neither helix nor lldb-vscode evaluate bash inlines.

[EDIT] - a workaround to get a version-independent path that tries to stay semi up-to-date:

Add this at the end of your $HOME/.zshrc:

# provide a version independent link to rustlib for the currently active rustc
rm -f "$HOME/.local/lib/rustlib" && mkdir -p "$HOME/.local/lib" && ln -s "$(rustc --print sysroot)/lib/rustlib" "$HOME/.local/lib/rustlib"

Then use this path for your languages.toml (replace PATH_TO_YOUR_HOME with whatever your $HOME is, sadly couldn't get around that part):

args = { program = "{0}", initCommands = [ "command script import /PATH_TO_YOUR_HOME/.local/lib/rustlib/etc/lldb_lookup.py", "command source -s 0 /PATH_TO_YOUR_HOME/.local/lib/rustlib/etc/lldb_commands" ] }

@quantonganh
Copy link
Contributor

The goal here is to find out how to pass these script/command to lldb-vscode. You're correct in suggesting the use of symlinks instead of hardcoding the sysroot path, By the way, I think we can use ln -sf command instead of running rm -f "$HOME/.local/lib/rustlib" everytime.

I will update the wiki based on your suggestion.

@HealsCodes
Copy link

You're right, ln -sf does the job nicely.

I'm over-all a bit unhappy with having to have a symlink that my shell profile updates as it doesn't cover for those cases where - on the off chance - I update my rust version or switch the active rust version.

In an ideal world we would be able to have some way to tell helix to expand environment variables or execute backtick or inline shell statements so the line could really be reduced to command script import $(rustc --print sysroot)/lib/... (or mayhap that would be a PR for lldb-vscode really I'm not sure who should have responsibility).

Thank you for updating the wiki - I think rust debugging is one of the more asked-for topics in Helix :)

@HealsCodes
Copy link

HealsCodes commented Aug 11, 2023

@quantonganh - I am so sorry for pinging yet again bit I believe I found an even more elegant solution that also gets rid of the downsides of creating a symlink.

Copy this python snippet to /usr/local/etc/lldb_vscode_rustc_primer.py:

import subprocess
import pathlib
import lldb

# determine the sysroot for the active rust interpreter
rustlib_etc = pathlib.Path(subprocess.getoutput('rustc --print sysroot')) / 'lib' / 'rustlib' / 'etc'
if not rustlib_etc.exists():
    raise RuntimeError('Unable to determine rustc sysroot')

# load lldb_lookup.py and execute lldb_commands with the correct path
lldb.debugger.HandleCommand(f"""command script import "{rustlib_etc / 'lldb_lookup.py'}" """)
lldb.debugger.HandleCommand(f"""command source -s 0 "{rustlib_etc / 'lldb_commands'}" """)

And then use this configuration for helix:

[[language]]
name = "rust"

[language.debugger]
name = "lldb-vscode"
transport = "stdio"
command = "lldb-vscode"

[[language.debugger.templates]]
name = "binary"
request = "launch"
completion = [ { name = "binary", completion = "filename" } ]
args = { program = "{0}", initCommands = [ "command script import /usr/local/etc/lldb_vscode_rustc_primer.py" ] }

The script takes care of querying the correct rustc sysroot and loading the bindings right at the moment when lldb-vscode is started and is 100% independent of symlinks or ARM / Intel / rust-up or homebrew setups as long as you have rustc in your system path.

@quantonganh
Copy link
Contributor

@Shirk Nice solution. Would you mind updating the wiki?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debug-adapter Area: Debug adapter client C-enhancement Category: Improvements
Projects
None yet
Development

No branches or pull requests

4 participants