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

Design a command language for interactive commandline / TUI rakudo-moarvm debugger #456

Open
timo opened this issue Dec 7, 2024 · 1 comment
Labels
moarvm Big changes to MoarVM

Comments

@timo
Copy link

timo commented Dec 7, 2024

The command language for App::MoarVM::Debug is currently ad-hoc, counter-intuitive, requires lots of typing to do relatively simple tasks, doesn't handle errors like typos sensibly, doesn't allow more than one command per line, and many more issues.

Here is the "help" output from the current iteration of the language, if you can call it that:

https://github.com/raku-community-modules/App-MoarVM-Debug/blob/9b0bea317fd992bc82d8a484df829032c6f0756c/lib/App/MoarVM/Debug.rakumod#L77-L181

This Problem Solving issue has the goal of writing a kind of command language that makes debugging more pleasant.

Here are properties for a command language to be used in a CLI debugger (but also available in TUI and GUI debuggers for power users?):

  • Vaguely familiar to users of existing debuggers
  • Ability to do repetitive things without much setup work
  • Ability to refer to results of earlier commands without much extra typing
  • Friendly to abbreviating commands and aliases
  • Easy to implement tab completion for
  • Allow bits and pieces of raku code in the commands where it makes sense
  • Commands should generally also Do The Right Thing when asynchronous operations are involved (await, react/supply blocks, ...)

There are some things that make stealing liberally from, for example GDB, difficult:

  • We can't just identify objects by their memory location like GDB, as they move around.
    • the moarvm remote protocol allows you to get a "handle" to an object, which is a sequentially increasing integer
    • a handle keeps an object alive so the garbage collector doesn't take it away while you could still refer to it
    • this means that currently the user has to manually clean up handles
  • Objects in Raku are of course more complex than structs. They have a meta-object protocol that controls aspects like what methods are available, or what types they match.
    • most operations you might want to do to an object will involve invoking code in the debuggee. the moar remote protocol supports this, but it's currently very tedious to do from the existing CLI.
    • Apart from the MOP, there's also the Associative and Positional roles that will very often be relevant, and there we should go through AT-POS / AT-KEY and friends.

You can not attach the moar remote to a process that hasn't been started with the debug port activated. We also now have an nqp::syscall(...) that can tell you if the debugger is on, so in theory, built-in classes can do some extra work when we have the debugger attached.
It already has a performance impact anyway, so if we do something like "for every Promise created, also store a traceback" it may be an acceptable price if we can benefit from the information in the debugger.

@timo timo added the fallback If no other label fits label Dec 7, 2024
@lizmat lizmat added moarvm Big changes to MoarVM and removed fallback If no other label fits labels Dec 7, 2024
@patrickbkr
Copy link
Member

The following is an unfinished brain-dump. It's missing aspects and commands and it does not tick all the boxes (e.g. allow more than one command per line) and it's biased (obviously). But I wanted to put it out now so we have something to shot down and to find out if the direction I'm thinking is right.

Some major topics of debugging:

Control execution

  • breakpoints
  • conditional breakpoints
  • A watch list
    • user supplied code
    • variables
  • the boring stuff (step in out over continue run)

Repeating previous debugging runs

  • The commands done in this session are kept in a log by default - such a log is called "debug script" (ds)
  • Easily inspect and edit a ds for re-runs
  • A number of previous dses are kept.
  • It's possible to write one out to a file for easy editing.
  • Can be started via a command line parameter or in the CLI.

Inspect the current state of execution

  • which threads are there
  • stack of those treads
  • variables in those threads
  • dynamic variables spooking around (and where they come from)
  • exception handlers
    • where did they come from?
    • where do they go to?
    • what's the payload?
  • global variables
  • Walking of nested content (objects, lists, hashes, ...) should be easily possible.
  • The user shouldn't be required to distinguish what a hash/list/object is when inspecting things / walking a datastructure.

Commands

  • [break|b] filename:line # Filename can be a regex. e.g. "b /inst/:123" would break on /home/patrickb/repos/my-prog/lib/Installation.rakumod:123
  • [break|b] filename:line { truthy code } # Will have to ponder which state code will need to be useful.
  • [break|b] { truthy code } # Break whenever the code goes truthy can do { $++ == 7 } to break on the 7th hit.
  • [run-to|rt] ... # same as break, except it directly starts running and ignores all other breakpoints until this breakpoint is hit. Does not add the break point to the list of BPs.
  • [watch|w] $some-var # Adds that variable to the watch list.
  • [watch|w] { code } # Adds that code to the watch list. I'm a bit unsure in which context that code should run.
  • [print-watch|pw] # Prints all the watched stuff
  • [list-script|ls] # Prints a list of the last 10 run scripts with timestamp, length of script, program.
  • [print-script|ps] num? # Prints the current script / script for the given number
  • [save-script|ss] file? # Writes the current script to a file, defaulting to "prog-name_2024-12-08T23:16:20+01.dbgs"; (dbgs == debug script)
  • [run-script|rs] [num | file]
  • [step-over|so|next|n]
  • [step-in|s]
  • [step-up|u]
  • [continue|c]
  • [restart]
  • [lexicals|l] 2-5 # In thread 2 in frame -5 list all lexicals. Thread and frame are both optional.
  • [globals|g] 2-5
  • [dynamics|d] 2-5
  • [print|p] 2-5 $var # In thread 2 in frame -5 print $var. When a thing with children is explicitly given, print it and all the children. (Pagination might be needed.) We'll need a syntax for describing a walk. Will the Raku access syntax work out for this use case? E.g. $Some::Module::my-obj.@attr[5]<foo>.$another-attr
  • [backtrace|bt] 2 # In thread 2. (optional)
  • [treads]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
moarvm Big changes to MoarVM
Projects
None yet
Development

No branches or pull requests

4 participants