-
Notifications
You must be signed in to change notification settings - Fork 16
Define Contracts for GDB_DEBUGGER_INTEGRATION #345
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
Merged
hendrikmennen
merged 2 commits into
one-ware:main
from
FEntwumS:feature/gdb-debugger-contracts
Aug 20, 2026
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
src/OneWare.Essentials/Debugger/Entities/DebugLaunchRequest.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| namespace OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| /// <summary> | ||
| /// What the user asked to debug. A request with neither an executable nor a remote endpoint is | ||
| /// valid — the backend then comes up without a target, which is what makes its command line | ||
| /// usable for checking the installation or attaching by hand. | ||
| /// <paramref name="RemoteEndpoint"/> is the whole remote seam: a plugin that brings up a target | ||
| /// passes the address it is listening on and never learns which backend connects. | ||
| /// </summary> | ||
| /// <param name="AdapterId">Identifies the backend, e.g. <c>GDB</c>.</param> | ||
| /// <param name="ExecutablePath"> | ||
| /// Path to the executable, e.g. an ELF file. Carries the program and its debug symbols. | ||
| /// </param> | ||
| /// <param name="RemoteEndpoint">Remote stub address, e.g. <c>localhost:1234</c>.</param> | ||
| /// <param name="WorkingDirectory">Working directory for the debug session.</param> | ||
| public sealed record DebugLaunchRequest( | ||
| string AdapterId, | ||
| string? ExecutablePath = null, | ||
| string? RemoteEndpoint = null, | ||
| string? WorkingDirectory = null); |
40 changes: 40 additions & 0 deletions
40
src/OneWare.Essentials/Debugger/Entities/DebugSessionState.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| namespace OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Everything the UI knows about the session and the target at one point in time. | ||
| /// A snapshot rather than a lifecycle enum plus a pile of separate events — the session | ||
| /// publishes a complete replacement on every change, so a panel binds one thing and cannot end | ||
| /// up showing registers from before the last step next to a frame from after it. | ||
| /// </summary> | ||
| public sealed record DebugSessionState | ||
| { | ||
| /// <summary> | ||
| /// No session, or a session that has ended. Also the state a session starts out in. | ||
| /// </summary> | ||
| public static DebugSessionState Empty { get; } = new(); | ||
|
|
||
| /// <summary> | ||
| /// <see langword="true"/> while the target is executing — nothing can be inspected and only | ||
| /// pausing is meaningful. | ||
| /// </summary> | ||
| public bool IsRunning { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// Where the target is halted, or <see langword="null"/> while it runs. | ||
| /// </summary> | ||
| public DebugStackFrame? CurrentFrame { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// Register contents as of the last halt. Empty while the target runs, and empty for a | ||
| /// backend that cannot read registers — the panel then simply shows nothing, which is what a | ||
| /// separate capability flag would have told it to do anyway. | ||
| /// </summary> | ||
| public IReadOnlyList<RegisterValue> Registers { get; init; } = []; | ||
|
|
||
| /// <summary> | ||
| /// Locals of <see cref="CurrentFrame"/> as of the last halt. Empty while the target runs, | ||
| /// and empty without debug symbols — a program linked without them has no names to report, | ||
| /// only registers. | ||
| /// </summary> | ||
| public IReadOnlyList<DebugVariable> Locals { get; init; } = []; | ||
| } |
20 changes: 20 additions & 0 deletions
20
src/OneWare.Essentials/Debugger/Entities/DebugStackFrame.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| namespace OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| /// <summary> | ||
| /// Where the target is halted. | ||
| /// </summary> | ||
| /// <param name="Function">Name of the function, if the backend reported one.</param> | ||
| /// <param name="File"> | ||
| /// Absolute source path, or <see langword="null"/> if the address could not be mapped. | ||
| /// The editor only jumps to the source location when this is set. | ||
| /// </param> | ||
| /// <param name="Line">One-based line number, or <c>0</c> if unknown.</param> | ||
| /// <param name="Address"> | ||
| /// Program counter as formatted by the backend, e.g. <c>0x00000108</c>. The only location | ||
| /// available when no debug symbols are present. | ||
| /// </param> | ||
| public sealed record DebugStackFrame( | ||
| string? Function, | ||
| string? File, | ||
| int Line, | ||
| string? Address); |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| namespace OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| /// <summary> | ||
| /// A local variable of the frame the target is halted in. | ||
| /// </summary> | ||
| /// <param name="Name">As it appears in the source.</param> | ||
| /// <param name="Value">Formatted by the backend; the UI displays the string unchanged.</param> | ||
| /// <param name="TypeName">Declared type, or <see langword="null"/> if the backend did not report one.</param> | ||
| public sealed record DebugVariable( | ||
| string Name, | ||
| string Value, | ||
| string? TypeName); |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| namespace OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| /// <summary> | ||
| /// A single register as read from the target. | ||
| /// </summary> | ||
| /// <param name="Name">As reported by the target, e.g. <c>sp</c> or <c>pc</c>.</param> | ||
| /// <param name="Value">Formatted by the backend; the UI displays the string unchanged.</param> | ||
| public sealed record RegisterValue( | ||
| string Name, | ||
| string Value); |
34 changes: 34 additions & 0 deletions
34
src/OneWare.Essentials/Debugger/Interfaces/IDebugAdapter.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| using OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| namespace OneWare.Essentials.Debugger.Interfaces; | ||
|
|
||
| /// <summary> | ||
| /// More of a session factory than a real adapter. The name is borrowed from VS Code's DAP | ||
| /// (Debug Adapter Protocol), where "debug adapter" is the term for the backend itself. | ||
| /// <see cref="CreateSession"/> is synchronous by intent, so that everything which can block or | ||
| /// fail happens in <see cref="IDebugSession.StartAsync"/> — one failure path instead of two. | ||
| /// </summary> | ||
| public interface IDebugAdapter | ||
| { | ||
| /// <summary> | ||
| /// Stable identifier, referenced by <see cref="DebugLaunchRequest.AdapterId"/>. | ||
| /// </summary> | ||
| public string Id { get; } | ||
|
|
||
| /// <summary> | ||
| /// Shown when the user picks a backend. | ||
| /// </summary> | ||
| public string DisplayName { get; } | ||
|
|
||
| /// <summary> | ||
| /// Returns <see langword="true"/> if this adapter can handle the given request. | ||
| /// Must be cheap and free of side effects — it decides whether to offer this adapter at all. | ||
| /// </summary> | ||
| public bool CanLaunch(DebugLaunchRequest launchRequest); | ||
|
|
||
| /// <summary> | ||
| /// Only constructs the session object; launching happens inside | ||
| /// <see cref="IDebugSession.StartAsync"/>. | ||
| /// </summary> | ||
| public IDebugSession CreateSession(DebugLaunchRequest launchRequest); | ||
| } |
36 changes: 36 additions & 0 deletions
36
src/OneWare.Essentials/Debugger/Interfaces/IDebugLaunchProvider.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using OneWare.Essentials.Debugger.Entities; | ||
|
|
||
| namespace OneWare.Essentials.Debugger.Interfaces; | ||
|
|
||
| /// <summary> | ||
| /// Analogous to <see cref="DebugLaunchRequest"/>, but as the preparation step. The core asks | ||
| /// which provider fits the current project, has it prepare, and starts with whatever request | ||
| /// comes back. That keeps the entry point in the generic UI while everything target-specific | ||
| /// stays in the plugin. | ||
| /// </summary> | ||
| public interface IDebugLaunchProvider | ||
| { | ||
| /// <summary> | ||
| /// Shown in the launch selection of the debug panel. | ||
| /// </summary> | ||
| public string DisplayName { get; } | ||
|
|
||
| /// <summary> | ||
| /// Returns <see langword="true"/> if this provider can handle the active project. | ||
| /// Must be cheap and free of side effects — the UI calls it to fill the selection. | ||
| /// </summary> | ||
| public bool CanPrepare(); | ||
|
|
||
| /// <summary> | ||
| /// Brings the target up and returns the matching launch request. | ||
| /// Returns <see langword="null"/> if preparation failed or was cancelled; the user has | ||
| /// already been notified in that case. | ||
| /// </summary> | ||
| public Task<DebugLaunchRequest?> PrepareAsync(CancellationToken ct = default); | ||
|
|
||
| /// <summary> | ||
| /// Releases whatever <see cref="PrepareAsync"/> claimed. Also runs when the session ended | ||
| /// on its own. | ||
| /// </summary> | ||
| public Task CleanupAsync(); | ||
| } |
114 changes: 114 additions & 0 deletions
114
src/OneWare.Essentials/Debugger/Interfaces/IDebugSession.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| using OneWare.Essentials.Debugger.Entities; | ||
| using OneWare.Essentials.EditorExtensions; | ||
|
|
||
| namespace OneWare.Essentials.Debugger.Interfaces; | ||
|
|
||
| /// <summary> | ||
| /// Encapsulates one debug session and exposes <see cref="DebugSessionState"/> to the UI. | ||
| /// Backend syntax does not cross this interface (no GDB/MI). | ||
| /// <see cref="SendRawCommandAsync"/> is the one deliberate exception — it backs the console's | ||
| /// command line. Control commands return no result: what the target did afterwards arrives | ||
| /// through <see cref="StateChanged"/>, which is also how an unsolicited halt (e.g. a breakpoint | ||
| /// being hit) reaches the panels. | ||
| /// </summary> | ||
| public interface IDebugSession | ||
| { | ||
| /// <summary> | ||
| /// Identifies the backend, e.g. <c>GDB</c>. | ||
| /// </summary> | ||
| public string AdapterId { get; } | ||
|
|
||
| /// <summary> | ||
| /// Latest published state. | ||
| /// </summary> | ||
| public DebugSessionState State { get; } | ||
|
|
||
| /// <summary> | ||
| /// Fired whenever <see cref="State"/> is replaced. May arrive on any thread. | ||
| /// </summary> | ||
| public event EventHandler<DebugSessionState>? StateChanged; | ||
|
|
||
| /// <summary> | ||
| /// Output of the debugged program, and readable messages from the backend. | ||
| /// </summary> | ||
| public event EventHandler<string>? OutputReceived; | ||
|
|
||
| /// <summary> | ||
| /// Every command sent to the backend, so the console can echo it. | ||
| /// </summary> | ||
| public event EventHandler<string>? CommandSent; | ||
|
|
||
| /// <summary> | ||
| /// The backend process ended, whether asked to or not. | ||
| /// </summary> | ||
| public event EventHandler? Exited; | ||
|
|
||
| /// <summary> | ||
| /// Brings the backend up and, for a remote request, attaches to the stub. | ||
| /// Returns <see langword="false"/> if it did not come up and the session is unusable. | ||
| /// </summary> | ||
| public Task<bool> StartAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Starts the program. Separate from <see cref="ContinueAsync"/> — an attached target is | ||
| /// already loaded and only needs resuming. | ||
| /// </summary> | ||
| public Task RunAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Resumes the halted target. | ||
| /// </summary> | ||
| public Task ContinueAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Halts the running target. | ||
| /// </summary> | ||
| public Task PauseAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Steps one source line, entering called functions. | ||
| /// </summary> | ||
| public Task StepIntoAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Steps one source line, stepping over called functions. | ||
| /// </summary> | ||
| public Task StepOverAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Runs until the current function returns. | ||
| /// </summary> | ||
| public Task StepOutAsync(); | ||
|
|
||
| /// <summary> | ||
| /// Arms a breakpoint on the target. | ||
| /// Returns <see langword="false"/> if the target refused it, e.g. because it ran out of | ||
| /// hardware breakpoints. | ||
| /// </summary> | ||
| public Task<bool> SetBreakpointAsync(BreakPoint breakpoint); | ||
|
|
||
| /// <summary> | ||
| /// Removes a previously armed breakpoint. | ||
| /// </summary> | ||
| public Task<bool> RemoveBreakpointAsync(BreakPoint breakpoint); | ||
|
|
||
| /// <summary> | ||
| /// Reads memory from the target. <paramref name="address"/> is whatever the backend accepts — | ||
| /// a literal such as <c>0x2001ff80</c>, or an expression like <c>&buffer</c> when symbols | ||
| /// exist. Returns <see langword="null"/> if the memory could not be read; a running target | ||
| /// cannot be read, so call only while halted. | ||
| /// </summary> | ||
| public Task<string?> ReadMemoryAsync(string address, int byteCount); | ||
|
|
||
| /// <summary> | ||
| /// Sends a command verbatim to the backend. The response arrives through | ||
| /// <see cref="OutputReceived"/>, like any other backend output. | ||
| /// </summary> | ||
| public Task SendRawCommandAsync(string command); | ||
|
|
||
| /// <summary> | ||
| /// Tears the backend down. Synchronous and best-effort — also runs on application shutdown, | ||
| /// where there is nothing left to await on. | ||
| /// </summary> | ||
| public void Stop(); | ||
| } |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.