Aliceserver is a debugger server implementing the DAP and MI protocols, using Alicedbg as the debugger back-end.
This is major work in progress! Don't expect it to replace GDB or LLDB any time soon.
Why?
- lldb-mi is generally no longer available as a prebuilt binary after LLDB 9.0.1.
- lldb and variants (including lldb-vscode/lldb-dap) all require the Python runtime.
- gdb-mi is fine, but GDC is generally unavailable for Windows.
- gdb-dap is written in Python and thus requires it.
- Mago, and mago-mi, are only available for Windows on x86/AMD64 platforms.
- All transport options in one package.
- Aliceserver provides future directions for features in Alicedbg.
Uses:
- Integrating your favorite text or code editor that implements a debugger UI.
- Automated debugging integration testing.
- Reusable high-level integration of Alicedbg.
Planned features:
- Multi-session support using TCP sockets.
- Multi-session support using UNIX sockets and Windows NamedPipes.
- Multi-session settings (unique session only, new session per connection).
+-------------------------------------------+
| Aliceserver |
| +---------------------------------------+ |
| | Server | |
| +---------------------------------------+ |
| ^ ^ ^ |
| | | | |
| | v v |
| | +----------+ +----------+ |
| v | Adapter | | Adapter | |
| +-----------+ +----------+ +----------+ |
| | Transport | | Debugger | | Debugger | |
+-+-----------+---+----------+-+----------+-+
^ ^ ^
v v v
+~~~~~~~~~+ +~~~~~~~~~~+ +~~~~~~~~~~+
| Client | | Process | | Process |
+~~~~~~~~~+ +~~~~~~~~~~+ +~~~~~~~~~~+
Aliceserver is implemented using an Object-Oriented Programming model.
The debugger server provides types and structures that the adapters and debuggers must interpret.
Aliceserver does not yet support multi-session.
Transports handle the transport of data from and to clients.
The medium can include streams, sockets, anything really.
Each transport classes inherit transport.ITransport
.
Available transports:
StdioTransport
: Implements a transport using standard streams.
Adapters have the responsability of handling the behavior of the given transport and the debugger instances.
Using the transport instance, adapters need to parse requests and send formatted replies and events back to the client via the transport instance.
Using the debugger instance, adapters need to interpret commands and handle debugger events.
After setting up instances, the server calls IAdapter.loop(ITransport, IDebugger)
.
Each adapter inherits adapter.IAdapter
.
Available adapters:
DAPAdapter
: Implements Debug Adapter Protocol as an adapter.MIAdapter
: Implements GDB's Machine Interface as an adapter.
Used to interface a debugger that manipulates processes.
Each debugger classes inherit debugger.IDebugger
.
Right now, only AlicedbgDebugger
is available as a debugger.
Debugger Adapter Protocol (DAP) is a HTTP-like JSON protocol that was introduced in vscode-debugadapter-node and was readapted as a standalone protocol for debugging various processes and runtimes in Visual Studio Code.
The protocol leaves a lot of nuance regarding implementation details, which can be a little infuriating to work with.
This chapter reuses terminology from DAP, such as Integer meaning, strictly
speaking, a 32-bit integer number (int
), and Number meaning a 64-bit
double-precision floating-point number (IEEE 754 double
).
DAP has two connection models: Single-session and multi-session.
- Single-session: Using standard I/O (stdio), a single adapter instance is started.
- Multi-session: Using TCP/IP, every new connection initiates a new debug session.
Messages are encoded as HTTP messages using the UTF-8 encoding.
Currently, there is only one header field, Content-Length
, that determines the
length of the message (payload). This field is read as an Integer.
The body (payload) is assumed to be encoded as JSON.
A typical request may look like this:
Content-Length: 82\r\n
\r\n
{"seq":1,"type":"request","command":"initialize","arguments":{"adapterId":"test"}}
And a typical response may look like this:
Content-Length: 81\r\n
\r\n
{"command":"initialize","request_seq":1,"seq":1,"success":true,"type":"response"}
Both client and server maintain their own sequence number, starting at 1.
NOTE: lldb-vscode starts their seq number at 0, while not as per specification, it poses no difference to its usage.
Implementation-specific details:
launch
request:arguments:path
: (Required) [String] File path.
attach
request:arguments:pid
: (Required) [Integer] Process ID.
Command support:
Command | Supported? | Comments |
---|---|---|
attach |
✔️ | __restart argument not supported. |
breakpointLocations |
❌ | |
completions |
❌ | |
configurationDone |
❌ | |
continue |
❌ | |
dataBreakpointInfo |
❌ | |
disassemble |
❌ | |
disconnect |
✔️ | |
evaluate |
❌ | |
exceptionInfo |
❌ | |
goto |
❌ | |
gotoTargets |
❌ | |
initialize |
✔️ | Locale is not supported. |
launch |
✔️ | noDebug and __restart are not supported. |
loadedSources |
❌ | |
modules |
❌ | |
next |
❌ | |
pause |
❌ | |
readMemory |
❌ | |
restart |
❌ | |
restartFrame |
❌ | |
reverseContinue |
❌ | |
scopes |
❌ | |
setBreakpoints |
❌ | |
setDataBreakpoints |
❌ | |
setExceptionBreakpoints |
❌ | |
setExpression |
❌ | |
setFunctionBreakpoints |
❌ | |
setInstructionBreakpoints |
❌ | |
setVariable |
❌ | |
source |
❌ | |
stackTrace |
❌ | |
stepBack |
❌ | |
stepIn |
❌ | |
stepInTargets |
❌ | |
stepOut |
❌ | |
terminate |
✔️ | |
terminateThreads |
❌ | |
threads |
❌ | |
variables |
❌ | |
writeMemory |
❌ |
Event | Supported? | Comments |
---|---|---|
breakpoint |
❌ | |
capabilities |
❌ | |
continued |
❌ | |
exited |
✔️ | |
initialized |
❌ | |
invalidated |
❌ | |
loadedSource |
❌ | |
memory |
❌ | |
module |
❌ | |
output |
❌ | |
process |
❌ | |
progressEnd |
❌ | |
progressStart |
❌ | |
progressUpdate |
❌ | |
stopped |
❌ | |
terminated |
❌ | |
thread |
❌ |
Machine Interface is a line-oriented protocol introduced in GDB 5.1.
In a typical setting, MI uses the standard streams to communicate with the child process.
Once the server starts running, it may already emit console streams, until
(gdb)\n
is printed, indicating that the server is ready to receive commands.
Commands are almost the same as you would use on GDB:
attach 12345\n
Replies to commands start with a ^
character:
^done\n
Or on error (note: \\n
and \\"
denote c-string formatting):
^error,msg="Example text.\\n\\nValue: \\"Test\\""\n
Events, console streams, logs, start with a significant unique character.
For example, command input (e.g., test\n
) will be replied as &"test\\n"\n
using c-string formatting.
Reply/Event | Character | Description |
---|---|---|
Result | ^ |
Used to reply to a command, if successful or errorneous. |
Exec | * |
Async execution state changed. |
Notify | = |
Async notification related to the debugger. |
Status | + |
Async status change. |
Console Stream | ~ |
Console messages intended to be printed. |
Target Stream | @ |
Program output when truly asynchronous, for remote targets. |
Log Stream | & |
Internal debugger messages. |
Some commands may start with -
.
NOTE: Command focus is on GDB, lldb-mi commands may work.
Request | Commands | Supported? | Comments |
---|---|---|---|
Attach | attach |
✔️ | |
Launch | -exec-run , target exec , -exec-arguments |
✔️ | |
Continue | -exec-continue |
✔️ | |
Terminate | -exec-abort |
✔️ | |
Detach | -exec-detach , detach |
✔️ | |
Set working directory | environment-directory |
✔️ | |
Disconnect | q , quit , -gdb-exit |
✔️ |
Request | Details | Supported? | Comments |
---|---|---|---|
Continued | ✔️ | ||
Exited | Reasons: exited , exited-normally |
✔️ | |
Output | ❌ | ||
Stopped | ❌ |
This project is licensed under the BSD-3-Clause-Clear license.