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

Tracepoints support #157

Open
cczetier opened this issue Nov 22, 2024 · 3 comments · May be fixed by #160
Open

Tracepoints support #157

cczetier opened this issue Nov 22, 2024 · 3 comments · May be fixed by #160
Labels
API-non-breaking Non-breaking API change new-protocol-extension New feature or request

Comments

@cczetier
Copy link

GDB has support for tracepoints (https://sourceware.org/gdb/current/onlinedocs/gdb.html/Tracepoints.html) for collecting information on the agent without needing to be driven by GDB. gdbstub currently doesn't support tracepoints in any capacity.

I'm currently working on a patch that adds "barebones" tracepoint support, which corresponds to parsing the packets related to setting up tracing experiments and reading the data back. Tracepoints are able to be configured with agent bytecode programs that record arbitrary information instead of only purely hitcounts as well, which is currently out of scope of the patch (and would possibly desire integration into with something like #40).

@cczetier
Copy link
Author

cczetier commented Nov 22, 2024

@daniel5151 in line with the discussion thread, my current extension trait looks like

pub trait Tracepoints: Target {
    fn tracepoints_init(&mut self)
        -> TargetResult<(), Self>;

    fn tracepoint_create(&self, tdp: NewTracepoint<<Self::Arch as Arch>::Usize>)
        -> TargetResult<(), Self>;
    fn tracepoint_define(&self, dtdp: DefineTracepoint<'_>)
        -> TargetResult<(), Self>;
    fn tracepoint_status(&self, tp: Tracepoint, addr: <Self::Arch as Arch>::Usize)
        -> TargetResult<(u64, u64), Self>;

    fn tracepoint_enumerate_start(&mut self)
        -> TargetResult<Option<NewTracepoint<<Self::Arch as Arch>::Usize>>, Self>;
    fn tracepoint_enumerate_step(&mut self)
        -> TargetResult<Option<DefineTracepoint<'_>>, Self>;

    fn trace_buffer_configure(&mut self, tb: TraceBuffer)
        -> TargetResult<(), Self>;
    fn trace_buffer_request(&mut self, offset: u64, len: usize, buf: &mut [u8])
        -> TargetResult<Option<usize>, Self>;

    fn trace_experiment_status(&self)
    -> TargetResult<ExperimentStatus<'_>, Self>;
    fn trace_experiment_start(&mut self)
        -> TargetResult<(), Self>;
    fn trace_experiment_stop(&mut self)
        -> TargetResult<(), Self>;

    fn select_frame(&mut self, frame: FrameRequest<<Self::Arch as Arch>::Usize>,
        report: &mut dyn FnMut(FrameDescription))
    -> TargetResult<(), Self>;

Most of them are fairly 1:1 with the corresponding packets in https://sourceware.org/gdb/current/onlinedocs/gdb.html/Tracepoint-Packets.html. I haven't yet implemented QTDV or QTfV/QTsV which are used for pulling variables out of the tracepoints: our constraints are such that we do want tracepoints to be able to be configured with bytecode programs, but they're fairly "opaque" because the tracepoint triggering component is separate from the gdbstub component (and so we can't have gdbstub driving behavior by executing the bytecode programs in response). That means that all the bytecode program execution is all handled by the target implementation and not gdbstub, so don't need the bytecode management piece.

@cczetier
Copy link
Author

Some of the APIs here are fairly annoying to wrap: the QTfP/QTsP type iterator state machine packets turned into tracepoint_enumerate_start/step because we can't actually keep around a generator object in gdbstub to drive by a subsequent step packet, for example. I couldn't think of a good way to compress the API or make it more misuse-resistant. I'm open to ideas on how to implement it instead.

@daniel5151 daniel5151 added new-protocol-extension New feature or request API-non-breaking Non-breaking API change labels Nov 22, 2024
@daniel5151
Copy link
Owner

I'm sure once there's an actual PR with code I can review, I'll have some more ideas / refinements to this proposed API, but this current sketch seems like a great jumping off point.

I must say though - its quite unfortunate that the current docs on these tracepoint packets simply say FIXME add detailed syntax, which makes it a bit harder for me to offer advice at the moment...


Some of the APIs here are fairly annoying to wrap: the QTfP/QTsP type iterator state machine packets turned into tracepoint_enumerate_start/step because we can't actually keep around a generator object in gdbstub to drive by a subsequent step packet, for example. I couldn't think of a good way to compress the API or make it more misuse-resistant. I'm open to ideas on how to implement it instead.

Skimming through the other packets gdbstub already supports, I wonder if looking at qfThreadInfo / qsThreadInfo might help here? Admittedly, looking at the code, it seems that I sidestepped the issue by simply sending back all the info as part of the qf response, and then unconditionally reporting "done" via the qs response... and based on the docs for these tracepoint packets, might not be a viable design.

For now, I think your proposed split API seems reasonable. Maybe once there's a PR out, I can suggest a better approach.

@cczetier cczetier linked a pull request Dec 11, 2024 that will close this issue
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API-non-breaking Non-breaking API change new-protocol-extension New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants