Skip to content

Explore impact of use zerocopy in gdbstub_arch deserialize impls #169

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

Open
daniel5151 opened this issue Mar 21, 2025 · 0 comments
Open

Explore impact of use zerocopy in gdbstub_arch deserialize impls #169

daniel5151 opened this issue Mar 21, 2025 · 0 comments
Labels
API-ergonomics Nothing's "broken", but the API could be improved design-required Getting this right will require some thought gdbstub_arch Related to code in `gdbstub_arch`

Comments

@daniel5151
Copy link
Owner

At the moment, most Arch implementations in gdbstub_arch use a variant of the following field-by-field pattern to deserialize registers from the wire into a Rust struct:

let mut regs = bytes[0..0x80]
    .chunks_exact(8)
    .map(|x| u64::from_le_bytes(x.try_into().unwrap()));

for reg in self.regs.iter_mut() {
    *reg = regs.next().ok_or(())?;
}

self.rip = u64::from_le_bytes(bytes[0x80..0x88].try_into().unwrap());
self.eflags = u32::from_le_bytes(bytes[0x88..0x8C].try_into().unwrap());

self.segments.gdb_deserialize(&bytes[0x8C..0xA4])?;

While I haven't looked at the generated asm yet, my suspicion is that LLVM isn't going to be clever enough to realize that this entire block of code can be implemented as a single memcpy from the bytes buffer, into the backing register struct (especially since, at this time, the backing structs aren't actually marked at repr(C, packed)).

It seems plausible that if we leverage zerocopy to write a safe impl of a buf-to-struct memcpy, we might see a noticeable simplification and reduction in generated asm.

Unfortunately - this would necessitate a breaking change, as adding repr(C, packed) to structs, and/or rearranging the layout of existing register structs would be a semver incompatible refactor.

An interesting follow-up thought: would it be possible to enable a truly zerocopy path here? e.g: change gdbstub APIs to expose the register struct with a lifetime tied back to the underlying packet buffer?


Regarding the serialize path - things are complicated by the fact that serialization is currently a streaming operation, where the gdb_serialize code invokes a callback in order to write out hex-bytes one at a time.

Theoretically, if we refactor the APIs to require the gdb_serialize code to require the use of zerocopy, it would be possible to tweak the contract to have gdbstub bulk-convert a returned &[u8].

More thought is required here.

@daniel5151 daniel5151 added API-ergonomics Nothing's "broken", but the API could be improved design-required Getting this right will require some thought gdbstub_arch Related to code in `gdbstub_arch` labels Mar 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API-ergonomics Nothing's "broken", but the API could be improved design-required Getting this right will require some thought gdbstub_arch Related to code in `gdbstub_arch`
Projects
None yet
Development

No branches or pull requests

1 participant