diff --git a/src/OneWare.Essentials/Debugger/Entities/DebugBreakPointFrame.cs b/src/OneWare.Essentials/Debugger/Entities/DebugBreakPointFrame.cs
new file mode 100644
index 00000000..33377662
--- /dev/null
+++ b/src/OneWare.Essentials/Debugger/Entities/DebugBreakPointFrame.cs
@@ -0,0 +1,29 @@
+namespace OneWare.Essentials.Debugger.Entities;
+
+///
+/// A place in the target. Used in both directions: the session reports where the target is
+/// halted, and a breakpoint asks it to halt somewhere. Both answer the same question — where —
+/// so both use the same type, and putting a breakpoint on the spot the target already stands on
+/// needs no conversion.
+/// Deliberately not the editor's own breakpoint model: while a published contract named that
+/// class, every change to the margin was a change to published API.
+///
+/// Name of the function, if the backend reported one. May also be set on
+/// its own to place a breakpoint on a function by name.
+///
+/// Absolute source path, or if the address could not be mapped — a
+/// program without debug symbols, code compiled without them, or a halt at an address the line
+/// table does not cover. Set on every breakpoint coming from the margin.
+/// The editor only jumps to the source location when this is set.
+///
+/// One-based line number. 0 means "unknown" when read from the target
+/// and "no line given" when written to it.
+///
+/// Program counter as formatted by the backend, e.g. 0x00000108. The only location
+/// available when no debug symbols are present.
+///
+public sealed record DebugBreakPointFrame(
+ string? Function,
+ string? File,
+ int Line,
+ string? Address);
diff --git a/src/OneWare.Essentials/Debugger/Entities/DebugLaunchRequest.cs b/src/OneWare.Essentials/Debugger/Entities/DebugLaunchRequest.cs
index ff05b612..e5c59284 100644
--- a/src/OneWare.Essentials/Debugger/Entities/DebugLaunchRequest.cs
+++ b/src/OneWare.Essentials/Debugger/Entities/DebugLaunchRequest.cs
@@ -7,14 +7,22 @@ namespace OneWare.Essentials.Debugger.Entities;
/// 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.
///
-/// Identifies the backend, e.g. GDB.
+/// Identifies the backend, e.g. GDB.
///
/// Path to the executable, e.g. an ELF file. Carries the program and its debug symbols.
///
/// Remote stub address, e.g. localhost:1234.
/// Working directory for the debug session.
+///
+/// Commands the backend applies at startup, before it connects to the target, in this order.
+/// Whoever brings a target up states here what the backend cannot learn from the executable
+/// alone — a register description, for instance. Passing them with the request keeps the
+/// handover in one place: the alternative is a file next to the executable whose name both
+/// sides have to agree on without either contract saying so.
+///
public sealed record DebugLaunchRequest(
- string AdapterId,
+ string BackendId,
string? ExecutablePath = null,
string? RemoteEndpoint = null,
- string? WorkingDirectory = null);
+ string? WorkingDirectory = null,
+ IReadOnlyList? InitCommands = null);
diff --git a/src/OneWare.Essentials/Debugger/Entities/RegisterValue.cs b/src/OneWare.Essentials/Debugger/Entities/DebugRegisterValue.cs
similarity index 89%
rename from src/OneWare.Essentials/Debugger/Entities/RegisterValue.cs
rename to src/OneWare.Essentials/Debugger/Entities/DebugRegisterValue.cs
index 15288c7e..06494438 100644
--- a/src/OneWare.Essentials/Debugger/Entities/RegisterValue.cs
+++ b/src/OneWare.Essentials/Debugger/Entities/DebugRegisterValue.cs
@@ -5,6 +5,6 @@ namespace OneWare.Essentials.Debugger.Entities;
///
/// As reported by the target, e.g. sp or pc.
/// Formatted by the backend; the UI displays the string unchanged.
-public sealed record RegisterValue(
+public sealed record DebugRegisterValue(
string Name,
string Value);
diff --git a/src/OneWare.Essentials/Debugger/Entities/DebugSessionState.cs b/src/OneWare.Essentials/Debugger/Entities/DebugSessionState.cs
index 2ceea45e..c9025a5d 100644
--- a/src/OneWare.Essentials/Debugger/Entities/DebugSessionState.cs
+++ b/src/OneWare.Essentials/Debugger/Entities/DebugSessionState.cs
@@ -22,14 +22,14 @@ public sealed record DebugSessionState
///
/// Where the target is halted, or while it runs.
///
- public DebugStackFrame? CurrentFrame { get; init; }
+ public DebugBreakPointFrame? CurrentFrame { get; init; }
///
/// 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.
///
- public IReadOnlyList Registers { get; init; } = [];
+ public IReadOnlyList Registers { get; init; } = [];
///
/// Locals of as of the last halt. Empty while the target runs,
diff --git a/src/OneWare.Essentials/Debugger/Entities/DebugStackFrame.cs b/src/OneWare.Essentials/Debugger/Entities/DebugStackFrame.cs
deleted file mode 100644
index b076e0c6..00000000
--- a/src/OneWare.Essentials/Debugger/Entities/DebugStackFrame.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace OneWare.Essentials.Debugger.Entities;
-
-///
-/// Where the target is halted.
-///
-/// Name of the function, if the backend reported one.
-///
-/// Absolute source path, or if the address could not be mapped.
-/// The editor only jumps to the source location when this is set.
-///
-/// One-based line number, or 0 if unknown.
-///
-/// Program counter as formatted by the backend, e.g. 0x00000108. The only location
-/// available when no debug symbols are present.
-///
-public sealed record DebugStackFrame(
- string? Function,
- string? File,
- int Line,
- string? Address);
diff --git a/src/OneWare.Essentials/Debugger/Interfaces/IDebugSession.cs b/src/OneWare.Essentials/Debugger/Interfaces/IDebugSession.cs
index f2efe466..e51187fe 100644
--- a/src/OneWare.Essentials/Debugger/Interfaces/IDebugSession.cs
+++ b/src/OneWare.Essentials/Debugger/Interfaces/IDebugSession.cs
@@ -1,5 +1,4 @@
using OneWare.Essentials.Debugger.Entities;
-using OneWare.Essentials.EditorExtensions;
namespace OneWare.Essentials.Debugger.Interfaces;
@@ -16,7 +15,7 @@ public interface IDebugSession
///
/// Identifies the backend, e.g. GDB.
///
- public string AdapterId { get; }
+ public string BackendId { get; }
///
/// Latest published state.
@@ -85,12 +84,13 @@ public interface IDebugSession
/// Returns if the target refused it, e.g. because it ran out of
/// hardware breakpoints.
///
- public Task SetBreakpointAsync(BreakPoint breakpoint);
+ public Task SetBreakpointAsync(DebugBreakPointFrame frame);
///
- /// Removes a previously armed breakpoint.
+ /// Removes a previously armed breakpoint. Removing one that is not armed counts as success —
+ /// the requested state is what matters, not how it was reached.
///
- public Task RemoveBreakpointAsync(BreakPoint breakpoint);
+ public Task RemoveBreakpointAsync(DebugBreakPointFrame frame);
///
/// Reads memory from the target. is whatever the backend accepts —
diff --git a/src/OneWare.Essentials/Debugger/Interfaces/IDebugAdapter.cs b/src/OneWare.Essentials/Debugger/Interfaces/IDebugSessionLauncher.cs
similarity index 57%
rename from src/OneWare.Essentials/Debugger/Interfaces/IDebugAdapter.cs
rename to src/OneWare.Essentials/Debugger/Interfaces/IDebugSessionLauncher.cs
index 17892d44..97f6548d 100644
--- a/src/OneWare.Essentials/Debugger/Interfaces/IDebugAdapter.cs
+++ b/src/OneWare.Essentials/Debugger/Interfaces/IDebugSessionLauncher.cs
@@ -3,26 +3,30 @@
namespace OneWare.Essentials.Debugger.Interfaces;
///
-/// 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.
+/// Turns a into a session for one particular backend. Together
+/// with it forms the whole chain: the preparer brings the
+/// target up and produces the request, the launcher decides who can serve it and builds the
+/// session.
+/// What VS Code's DAP calls a "debug adapter" is this — the name is deliberately not borrowed,
+/// because this one is in-process and never speaks the protocol.
/// is synchronous by intent, so that everything which can block or
/// fail happens in — one failure path instead of two.
///
-public interface IDebugAdapter
+public interface IDebugSessionLauncher
{
///
- /// Stable identifier, referenced by .
+ /// Stable identifier, referenced by .
///
public string Id { get; }
///
- /// Shown when the user picks a backend.
+ /// Human-readable name of the backend, e.g. GNU Debugger.
///
public string DisplayName { get; }
///
- /// Returns 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.
+ /// Returns if this launcher can serve the given request.
+ /// Must be cheap and free of side effects — it decides whether this launcher is used at all.
///
public bool CanLaunch(DebugLaunchRequest launchRequest);
diff --git a/src/OneWare.Essentials/Debugger/Interfaces/IDebugLaunchProvider.cs b/src/OneWare.Essentials/Debugger/Interfaces/IDebugTargetPreparer.cs
similarity index 59%
rename from src/OneWare.Essentials/Debugger/Interfaces/IDebugLaunchProvider.cs
rename to src/OneWare.Essentials/Debugger/Interfaces/IDebugTargetPreparer.cs
index 7beb1871..57a5ddf7 100644
--- a/src/OneWare.Essentials/Debugger/Interfaces/IDebugLaunchProvider.cs
+++ b/src/OneWare.Essentials/Debugger/Interfaces/IDebugTargetPreparer.cs
@@ -4,29 +4,31 @@ namespace OneWare.Essentials.Debugger.Interfaces;
///
/// Analogous to , but as the preparation step. The core asks
-/// which provider fits the current project, has it prepare, and starts with whatever request
+/// which preparer 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.
///
-public interface IDebugLaunchProvider
+public interface IDebugTargetPreparer
{
///
- /// Shown in the launch selection of the debug panel.
+ /// Names the preparer in the status line and in the debug console.
///
public string DisplayName { get; }
///
- /// Returns if this provider can handle the active project.
- /// Must be cheap and free of side effects — the UI calls it to fill the selection.
+ /// Returns if this preparer can handle the active project.
+ /// Must be cheap and free of side effects — the UI calls it to pick a preparer.
///
public bool CanPrepare();
///
- /// Brings the target up and returns the matching launch request.
- /// Returns if preparation failed or was cancelled; the user has
- /// already been notified in that case.
+ /// Brings the target up and returns the matching launch request. A running preparation
+ /// cannot be aborted; the UI locks the start button and waits for it, so keep the steps
+ /// short and report what is happening.
+ /// Returns if preparation failed; the user has already been notified
+ /// in that case.
///
- public Task PrepareAsync(CancellationToken ct = default);
+ public Task PrepareAsync();
///
/// Releases whatever claimed. Also runs when the session ended
diff --git a/src/OneWare.Essentials/Debugger/Interfaces/IDebuggerService.cs b/src/OneWare.Essentials/Debugger/Interfaces/IDebuggerService.cs
index defc105b..fa9fede4 100644
--- a/src/OneWare.Essentials/Debugger/Interfaces/IDebuggerService.cs
+++ b/src/OneWare.Essentials/Debugger/Interfaces/IDebuggerService.cs
@@ -12,13 +12,13 @@ public interface IDebuggerService
///
/// Registered backends, including the core's own.
///
- public IReadOnlyList Adapters { get; }
+ public IReadOnlyList SessionLaunchers { get; }
///
- /// Registered launch providers. Whoever fits the active project shows up in the launch
- /// selection of the debug panel.
+ /// Registered target preparers. Starting the debugger picks the first one whose
+ /// accepts the active project.
///
- public IReadOnlyList LaunchProviders { get; }
+ public IReadOnlyList TargetPreparers { get; }
///
/// The active session, or if none is running.
@@ -43,29 +43,29 @@ public interface IDebuggerService
public event EventHandler? StateChanged;
///
- /// Registers an adapter. Resolved from the container — the implementation gets constructor
+ /// Registers an launcher. Resolved from the container — the implementation gets constructor
/// injection like any other service.
///
- public void RegisterAdapter() where T : IDebugAdapter;
+ public void RegisterSessionLauncher() where T : IDebugSessionLauncher;
///
- /// Registers a launch provider. Resolved from the container like adapters.
+ /// Registers a target preparer. Resolved from the container like session launchers.
///
- public void RegisterLaunchProvider() where T : IDebugLaunchProvider;
+ public void RegisterTargetPreparer() where T : IDebugTargetPreparer;
///
/// Starts a session, arms the breakpoints currently set in the editor and runs the program.
- /// Returns if no adapter accepted the request or the backend did not
+ /// Returns if no launcher accepted the request or the backend did not
/// come up; nothing is left running in that case.
///
public Task StartAsync(DebugLaunchRequest launchRequest);
///
- /// Calls first, then starts with the
- /// returned request. runs as soon as the
+ /// Calls first, then starts with the
+ /// returned request. runs as soon as the
/// session ends, no matter how it ended.
///
- public Task StartAsync(IDebugLaunchProvider provider, CancellationToken ct = default);
+ public Task StartAsync(IDebugTargetPreparer preparer);
///
/// Ends the active session. Does nothing if none is running.