(API Overhaul) Trait-based Protocol Extensions#24
Closed
daniel5151 wants to merge 12 commits intomasterfrom
Closed
(API Overhaul) Trait-based Protocol Extensions#24daniel5151 wants to merge 12 commits intomasterfrom
daniel5151 wants to merge 12 commits intomasterfrom
Conversation
Honestly, I'm pretty happy with how this is looking. This current approach is reminiscent of a C-style struct-of-function-pointers implementation, but with Traits instead. I thought of this approach a while back, but never got around to implementing it. Glad I found the time though, since it's really cool! While the API is somewhat "unorthadox", the final implementations look quite clean, and are easier to follow than having the single monolithic `Target` method as in previous versions. Plus, I was able to remove the gnarly `OptResult` type, which I always felt was really dirty! Similarly, the internal implementation could be cleaned up quite a bit as well, since checking for a supported feature doesn't actually requite _invoking_ an associated method. Just check if the ops "pointer" is None or not! * * * There are a couple more things I'd like to experiment with: - is there some way that GdbStub's internal implementation can be broken-up similarly to the public API? i.e: is there some way to move the packet parsing + handler code for, say, `handle_monitor_cmd` into it's own little module, which could then be dead-code-eliminated if a target doesn't end up using that feature? - more generally, what's the overhead of this abuse-of-dyn-traits approach? I vaguely recall playing around with this idea in godbolt, and being surprised by how effective the compiler was able to inline everything, though I should probably run some more proper experiments... - Heck, that would probably be an interesting topic for a blog post!
oh boy, did I just write a good chunk of my next blog post??
After all, there's no need for the "specify the operation using an enum" hack anymore. The two operations can be independant methods, and the Rust compiler will enforce that both must be implemented!
If a target doesn't implement the `MonitorCmd` extension, then it seems like a shame to have it include a bunch of unused code related to parsing + handling `qRcmd` packets, right? Well, with some clever match guard hinting + the power of Inline Dyn Extension Traits, it's possible to trick the Rust compiler into optimizing unused packets out of the final binary! Now, i'm no compiler engineer, so I can't say whether or not this optimization is "guaranteed" to occur or not. That said, given how simple the __protocol_hint method is, and how it can monomorphize to a static `true / false` boolean, I strongly suspect that it will almost always perform the optimization. To assist in implementing + debugging this feature, I've included a new internal `__dead_code_marker!` macro (and associated feature), which are used by `script/test_dead_code_elim.sh` to check whether or not a certain packet is optimized out in the example binaries. See the inline documentation for how that script works...
Ughh, it took a long while, but I've finally come up with an API for multiprocess support that I'm happy with, _and_ fixed some icky hacks and bad implementation choices in the core gdbstub implementation. Some interesting things that come out of this (chonker of a) commit: - Turns out the `qC` packet is totally useless, so I've gone ahead and removed it entirely. The less code the better. - I've finally fixed the incredibly confusing naming scheme surrounding the thread-id structures. The new names should be much more sane (and have less overlap) - I've massively improved the `resume` method for multithreaded targets. The key insight is that returning a tuple of `(Tid, StopReason)` wasn't exactly correct, as there are certain stop reasons that are _not_ associated with any Tid (e.g: GDB interrupt), and it effectively forced the target to "flip a coin" as to which Tid it reported. This old system wreaked havoc when dealing with breakpoints in multithreaded systems, but with the new `ThreadStopReason` API, i've managed to clean up the library internals to keep the GDB nice and happy, and removed the burden of making arbitrary decisions from the Targer implementation. - vCont works now! I'm a dummy, and never actually realized that my vCont implementation was totally busted. I've gone ahead and fixed it, so it should be working now.
hmm, not sure when this bug was introduced... Well, it's fixed now, so that's good.
just a few things that I noticed while rummaging around in the codebase. they don't really merit individial commits...
While there are still many external types annotated with `#[derive(Debug)]`, I've removed the debug impls for internal types, to assist in code size reduction.
Upon further thought, I've realized that using the unit type as the "unimplemented" RegId type is actually quite detrimental to the end-user experience. It forces the user to fork `gdbstub` if they want to implement the `read/write_register` methods for a built in architecure, which could drive users away... By passing through the raw GDB identifier, it gives users a chance to "rough it out" on their own, while urging them to upstream their implementations as well.
794f56c to
5b51d61
Compare
Owner
Author
|
(these changes have been merged into master, so I'm closing this draft PR) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a pretty massive API overhaul which uses a pretty nifty type-system + compiler optimization trick to emulate optional trait methods at compile time (along with a bunch of other useful properties, such as compile-time trait method grouping / mutual exclusion, and improved performance).
As far as I can tell, I'm the first one to stumble across this hack (and/or make such extensive use of it), so I've given it the working title of "Inlineable Dyn Extension Traits" (IDETs). I'm already working on a writeup that talks about this technique! See https://github.com/daniel5151/optional-trait-methods
Technical details aside, the end-result of this PR is to make the Target API significantly more robust for end users, along with simplifying a lot of the GdbStub internals that handle OptResult and the MaybeUnimpl.
Scope-wise, this PR doesn't touch any code outside of the
gdbstub_implandtargetmodules. Notably, thearchmodule is left completely unchanged.