Invoking the shell will cause it to persist across the entire build and
to re-execute whenever the builder pauses at another location again.
This still requires using `exec` to launch the shell. Launching by frame
id is also removed since it no longer applies to this version.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Change how breakpoints and stepping works. These now work more how you
would expect another programming language to work. Breakpoints happen
before the step has been invoked rather than after which means you can
inspect the state before the command runs.
This has the advantage of being more intuitive for someone familiar with
other debuggers. The negative is that you can't run to after a certain
step as easily as you could before. Instead, you would run to that stage
and then use next to go to the step directly afterwards.
Step in and out also now have different behaviors. When a step has
multiple inputs, the inputs of non-zero index are considered like
"function calls". The most common cause of this is to use `COPY --from`
or a bind mount. Stepping into these will cause it to jump to the
beginning of the call chain for that branch. Using step out will exit
back to the location where step in was used.
This change also makes it so some steps may be invoked multiple times in
the callgraph if multiple steps depend on them. The reused steps will
still be cached, but you may end up stepping through more lines than the
previous implementation.
Stack traces now represent where these step in and step out areas
happen rather than the previous steps. This can help you know from where
a certain step is being used.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Supports using the `evaluate` request in REPL mode to start a container
with the `exec` command. Presently doesn't support any arguments.
This improves the dap server so it is capable of sending reverse
requests and receiving the response. It also adds a hidden command
`dap attach` that attaches to the socket created by `evaluate`.
This requires the client to support `runInTerminal`.
Likely needs some additional work to make sure resources are cleaned up
cleanly especially when the build is unpaused or terminated, but it
should work as a decent base.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Step into and step out are required by the UI for DAP. We don't have a
way to implement these in a logical manner but they need to exist. We'll
discuss in further iterations how these might differ from next and
continue, but for now, we just need some implementation for the UI.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Implement variable references to inspect the state of a stack frame.
Variable reference ids are composed of two sections. A thread mask that
is the first 8 bytes and the remainder is an increasing number that gets
reset each time a thread is resumed. This allows the adapter to know
which thread to delegate the variables request to and allows the
variable references to still remain confined to each thread. An int32 is
used for this because variable references need to be in the range of
(0, 2^32).
At the moment, only the platform variables and some of the exec
operations for an operation. These are labeled as "arguments" to the
stack frame.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Implement the first iteration of breakpoints. When a breakpoint is set,
it starts unverified. When a thread begins evaluation, it tries to see
if a breakpoint corresponds to one of the parsed instructions and will
verify it.
Breakpoints work when continue is used.
At the current moment, setting breakpoints while a thread is currently
running doesn't work. Breakpoints are rechecked each time execution is
about to restart.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
This will configure the default behavior when beginning to evaluate a
build target. When `stopOnEntry` is used, it will default to `stepNext`.
Otherwise, `stepContinue` will be used.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
It is now possible to send next and continue as separate signals. When
executing a build, the debug adapter will divide the LLB graph into
regions. Each region corresponds to an uninterrupted chain of
instructions. It will also record which regions depend on which other
ones.
This determines the execution order and it also determines what the
stack traces look like.
When continue is used, we will attempt to evaluate the last leaf node
(the head). If we push next, we will determine which digest would be the
next one to be processed.
In the future, this will be used to also support breakpoints.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Adds a simple implementation of the debug adapter that supports the very
basics of a debug adapter.
It supports the launch request, the configuration done request, the
creation of threads, stopping, resuming, and disconnecting from server.
It does not support custom breakpoints, stack traces, or variable
inspection yet. These are planned to be added in the future.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>