Open daniel5151 opened 3 years ago
I have spent quite a bit of time toying around with this, and ended up hacking together an implementation that works, but misses the mark in terms of API ergonomics. The code is available on the feature-draft/agent
branch.
The biggest issue with that implementation is that the API forces users to do some "ownership gymnastics" in order to work correctly. In a nutshell, I structured the Agent API the same way I would any other protocol extension: as a direct IDET of the Target
trait. This had the unfortunate side-effect that it tied that BytecodeStorage
and BytecodeExecutor
lifetimes directly to the target, which is really bad, since the BytecodeExecutor
needs to mutably modify the target while at the same time immutably borrowing the bytecode expression from the BytecodeStorage
- which is part of the target itself!
I spent a bit more time poking away at the implementation, and while I feel like it is salvageable, I don't think I have the mental energy to keep iterating on it. As such, I've extracted the relevant code and put it into the aforementioned feature-draft/agent
branch, with the expectation that I will salvage bits-and-pieces of the implementation when I eventually get around to re-visiting this feature.
That said, it does in-fact work, and if you run the armv4t
example on that branch, you should be able to set conditional breakpoints that get executed on the target! It also demonstrates how to use khuey/gdb-agent
as a bytecode executor.
If you stumble across this issue, and you're interested in seeing this get implemented, feel free to leave a comment and/or help out with an implementation!
FWIW I think the heavy part of making gdb-agent work in no_std
is dealing with the error handling. Beyond that I doubt it would be too bad.
See https://sourceware.org/gdb/current/onlinedocs/gdb/Agent-Expressions.html#Agent-Expressions
One notable application of Agent Expressions not included in this overview is that breakpoint packets support specifying conditions and/or commands as bytecode expressions to be executed directly on the device. This enables significantly faster conditional breakpoints, as the target does not have to stop execution, communicate with the remote GDB client, and wait for the client to execute the condition.
There are several considerations to keep in mind while working on this feature and designing its API:
gdbstub
should parse packets with bytecode expressions and extract the bytecode expression slices, but should not decide how they are stored / retrieved.BytecodeStorage
trait, which users provide the implementation of.gdbstub
must include at least one "batteries included" implementation to make it as easy as possible to get up and running with the feature. e.g: if thestd
feature is enabled, provide aHashMap
-based implementation.gdbstub
should not lock users into a single bytecode interpreter. Users should have the flexibility to decide how/when bytecode expressions are be executed.BytecodeExecutor
trait, which users provide the implementation of.gdbstub
should offer a "batteries included" interpreter for those that just want to get up and running quickly (but this wouldn't be a feature blocker)Some final things of note:
BytecodeExecutor
implementation that can be used to validate the feature is working as intended!gdbstub
included an "in-house" Agent Bytecode executor (withno_std
support), but that's not a feature blocker