V5 Debugger Server Protocol v2
Authors & Copyright
All programming, documentation, and spec authoring was done by Hunter Stasonis
This program and its documentation have been placed under the MIT License, and is provided without warranty of any kind
Constants and Definitions
Throughout this document many words many be underlined with a dotted line, hovering over these words will show their definition.
Changes since v1
Version 2 of the debug server protocol introduces features for breakpoints, and setting variable memory along with adding subargument brackets around data field arguments in some message types.
Since message types which where introduced in a previous version of the protocol have been modified, version 2 should be considered not backwards-compatible.
If you wish to view the previous protocol documentation use the version switcher at the top of the screen.
Notes on literals
Some literals such as true and false are used on this page, their values should not be interpreted as their String names but instead their actual value. Hovering over literals will show their actual values.
Try it out!
What is the value of true? Hover over the next word: true
What is the value of false? Hover over the next word: false
Communication
v5dbg communicates over USB serial. The debug server opens the pseudofile provided by the PROS kernel located at /ser/sout in write mode, messages are serialized and written to this file using fwrite. COBS and stream multiplexing should be disabled for this file so data can be read raw by the debugger.
Messages
Messages are payloads of data sent from either the debugger, or debug server. All messages are formatted as follows, left to right.
- Message begin
- Protocol version
- Message type
- Message payload
- Newline
An example message can be seen as %2:1:0, message type 1 is program suspend. It should be noted that if more than two message separator characters are used then any located after the third are ignored and are merged into the message payload.
If we have the message %2:2:0:1:2:3 then the message payload should be 0:1:2:3, the extra message separator characters do not mess up the parser state and does not throw a warning or error of any kind
Message Types
Message types are defined as enums within v5dbg/protocol.h (include directory), the DEBUGGER_MESSAGE_MAX is used as a basic check to determine if a message type is invalid.
Message IDs can be considered unsigned ints since they never can be negative, and a message should be assumed invalid or corrupted if so.
enum v5dbg_message_type_e
{
/// @brief Connection opened
DEBUGGER_MESSAGE_OPEN = 0,
/// @brief Request program suspension, assume it has occurred when a DEBUG_MESSAGE_RSUSPEND is parsed
DEBUGGER_MESSAGE_SUSPEND = 1,
/// @brief Connection closed
DEBUGGER_MESSAGE_CLOSE = 2,
/// @brief Allocate a string, can be processed by the debugger however it likes
DEBUGGER_MESSAGE_ALLOCATE_STRING = 3,
/// @brief Resume the program from a suspended state
DEBUGGER_MESSAGE_RESUME = 4,
/// @brief Respond with DEBUGGER_MESSAGE_RTHREADS containing a comma separated list of every thread being managed by
/// v5dbg
DEBUGGER_MESSAGE_THREADS = 5,
/// @brief Return message for DEBUGGER_MESSAGE_THREADS
DEBUGGER_MESSAGE_RTHREADS = 6,
/// @brief Get the vstack for the given thread index
DEBUGGER_MESSAGE_VSTACK_FOR = 7,
/// @brief Return message for DEBUGGER_MESSAGE_VSTACK_FOR, keep accepting messages until DEBUGGER_MESSAGE_VSTACK_END
DEBUGGER_MESSAGE_RVSTACK = 8,
/// @brief Stop accepting DEBUGGER_MESSAGE_RVSTACK messages
DEBUGGER_MESSAGE_VSTACK_END = 9,
/// @brief List memory for the given stack frame with thread ID
DEBUGGER_MESSAGE_LMEM_FOR = 10,
/// @brief Returned message for DEBUGGER_MESSAGE_LMEM_FOR, keep accepting messages until DEBUGGER_MESSAGE_LMEM_END
DEBUGGER_MESSAGE_RLMEM = 11,
/// @brief Stop accepting DEBUGGER_MESSAGE_RLMEM messages
DEBUGGER_MESSAGE_LMEM_END = 12,
/// @brief Sent to the debugger every time a breakpoint is activated and the program is suspended
DEBUGGER_MESSAGE_BREAK_INVOKED = 13,
/// @brief List all breakpoints registered in the program
DEBUGGER_MESSAGE_LBREAKPOINTS = 14,
/// @brief Sent for every breakpoint registered with the debug server
DEBUGGER_MESSAGE_RBREAKPOINT = 15,
/// @brief Stop accepting DEBUGGER_MESSAGE_RBREAKPOINT messages
DEBUGGER_MESSAGE_END_BREAKPOINTS = 16,
/// @brief Sent to the debug server in order to disable/enable a breakpoint by ID
DEBUGGER_MESSAGE_BREAKPOINT_SET_STATUS = 17,
/// @brief Set the contents of the memory which is backing a variable
DEBUGGER_MESSAGE_MEMORY_SET = 18,
/// @brief Used to return information and state of a memory set call
DEBUGGER_MESSAGE_RMEMORY_SET = 19,
/// @brief Max debugger message ID
DEBUGGER_MESSAGE_MAX = 20
};
Subarguments
Subarguments introduce a way for messages to include more complex data in their 3rd data field. Since the message parser only parses up to the 2nd message separator character the third data field can have message separators located in it.
The subargs parser allows for another array of elements to be placed into the data field, the simplest way to perform this would be to split the data field on the message separator character. If we want to include data inside the data field that has message separators(such as C++ typenames) we need an escape character.
The [ and ] character
When the first character of an element is an [ we ignore any message separator characters we come across until we encounter a ] character located before a message separator or a newline.
Without subarguments
Imagine we have this message:
%2:1:std::vector<int>:helloWorld
It's parameters are broken down into:
11std::vector<int>:helloWorld
When we split the data parameter of the message by the message separator we get:
std:vector<int>helloWorld
This IS NOT what we want!
With subarguments
Taking our old string from the previous example and adding subargumrnts we get:
%2:1:[std::vector<int>]:helloWorld
It's parameters are broken down the same way during message parsing
Now instead of splitting on the message seperator the subargument parser is called creating:
std::vector<int>helloWorld
This IS what we want!
Variable set mode
The variable set mode dictates the behavior of the `DEBUGGER_MESSAGE_MEMORY_SET message.
Notice
Use the actual value of each enum and not its string name.
enum v5dbg_variable_set_mode_e
{
/// @brief Set the memory of this variable once
VARIABLE_SET_MODE_SINGLE = 0,
/// @brief Set the memory of this variable even after its reallocated
VARIABLE_SET_MODE_CONST = 1
};
Behaviors
Messages may be marked with icons, hovering over them will show information about the specific message type. Messages that do not state their argument type can be assumed to not use subarguments, or comma splitting.
If messages have more than one argument they will specify their argument type next to their enum name in the title.
DEBUGGER_MESSAGE_OPEN
Sent by the debug server to the debugger at program startup and every 2 seconds that the program is running. The debugger will only connect to the debug server if it can detect and read this message, the debugger will also print a hang message if it fails to receive an OPEN message atleast once every 5 seconds.
DEBUGGER_MESSAGE_ALLOCATE_STRING
When sent to the debug server this message sent unaltered back to the debugger, this was used for testing.
DEBUGGER_MESSAGE_SUSPEND
Requests the debug server to suspend all of it's supervised tasks, no response is sent to the client.
DEBUGGER_MESSAGE_RESUME
Requests the debug server to resume all of it's supervised tasks, no response is sent to the client.
DEBUGGER_MESSAGE_THREADS
Responds with a single DEBUGGER_MESSAGE_RTHREADS message containing all the debugger's supervised threads.
DEBUGGER_MESSAGE_RTHREADS
Response to a DEBUGGER_MESSAGE_THREADS message.
The following parameters repeat for every thread.
| Parameter | Docs |
|---|---|
| Index 0 | String Name of the thread |
| Index 1 | unsigned int ID of the thread |
Example message
%2:6:Worker Thread,0,Odom Thread,1,OpControl,2
DEBUGGER_MESSAGE_VSTACK_FOR
When sent to the debug server it returns a series of DEBUGGER_MESSAGE_RVSTACK messages for each frame of the stack before ending with a DEBUGGER_MESSAGE_VSTACK_END message.
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int Thread ID to grab the callstack for |
DEBUGGER_MESSAGE_RVSTACK
This message is sent repeatedly until a DEBUGGER_MESSAGE_VSTACK_END message is sent.
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int of the frame ID |
| Index 1 | String Name of the function |
| Index 2 | String File path to the function |
| Index 3 | unsigned int Line number inside of the file where this function begins |
DEBUGGER_MESSAGE_VSTACK_END
This message is sent to signal that the debugger can stop waiting for DEBUGGER_MESSAGE_RVSTACK messages.
The data field may be filled with any data the server wishes but it can be ignored.
DEBUGGER_MESSAGE_LMEM_FOR
This message is sent to the debug server to request a series of DEBUGGER_MESSAGE_RLMEM messages terminated by a DEBUGGER_MESSAGE_LMEM_END which contains captured local memory.
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int Frame ID |
| Index 1 | unsigned int Thread ID |
DEBUGGER_MESSAGE_RLMEM
This message is sent repeatedly until a DEBUGGER_MESSAGE_LMEM_END message is sent.
| Parameter | Docs |
|---|---|
| Index 0 | String C++ typename of this variable |
| Index 1 | String Name of this variable |
| Index 2 | String Path to the file this variable is in |
| Index 3 | unsigned int Line number this variable was exposed on |
| Index 4 | String Pretty printed buffer for this variable |
DEBUGGER_MESSAGE_LMEM_END
This message is sent to signal that the debugger can stop waiting for DEBUGGER_MESSAGE_RLMEM messages.
The data field may be filled with any data the server wishes but it can be ignored.
DEBUGGER_MESSAGE_BREAK_INVOKED
This message is sent from the debug server to the debugger when a breakpoint is tripped. By the time this message is parsed it can be assumed that the program is suspended and can be resumed with a call to DEBUGGER_MESSAGE_RESUME
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int ID of this breakpoint |
| Index 1 | String Name of this breakpoint |
| Index 2 | String Path to the file this breakpoint is in |
| Index 3 | unsigned int Line number this breakpoint was placed on |
DEBUGGER_MESSAGE_LBREAKPOINTS
Responds with a series of DEBUGGER_MESSAGE_RBREAKPOINT messages for each registered breakpoint.
| Parameter | Docs |
|---|---|
| Index 0 | bool If set to true then "hidden" breakpoints are returned |
DEBUGGER_MESSAGE_RBREAKPOINT
This message is sent repeatedly until a DEBUGGER_MESSAGE_END_BREAKPOINTS message is sent
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int Breakpoint ID |
| Index 1 | String Function that breakpoint is in |
| Index 2 | String Path to the file that the breakpoint is in |
| Index 3 | unsigned int Line number which this breakpoint is on |
DEBUGGER_MESSAGE_END_BREAKPOINTS
This message is sent to signal that the debugger can stop waiting for DEBUGGER_MESSAGE_RBREAKPOINT messages.
The data field may be filled with any data the server wishes but it can be ignored.
DEBUGGER_MESSAGE_BREAKPOINT_SET_STATUS
Request the debug server to change the status of a breakpoint, no response is sent to the client.
| Parameter | Docs |
|---|---|
| Index 0 | unsigned int Breakpoint ID |
| Index 1 | bool true to enable to breakpoint, false to disable |
DEBUGGER_MESSAGE_MEMORY_SET
Request the debug server to set the value of a variable to the given value, a DEBUGGER_MESSAGE_RMEMORY_SET message is sent upon completion.
| Parameter | Docs |
|---|---|
| Index 0 | String Name of the variable to set |
| Index 1 | String Data to set the variable too, data is converted to the correct data type server-side |
| Index 2 | unsigned int Stack frame where this variable is located |
| Index 3 | unsigned int Thread ID where the stack frame is located |
| Index 4 | v5dbg_variable_mode_e Variable set mode |
DEBUGGER_MESSAGE_RMEMORY_SET
Sent after a DEBUGGER_MESSAGE_MEMORY_SET operation is completed.
The data field consists of a String value which corresponds to the completion status of the operation.
If the value in the data field is 0x0 (String literal) the debug server should attempt to clear the recopy buffer which was allocated on a constant copy set memory operation.
| Result value | Help |
|---|---|
MemorySet |
Success message, the operation completed |
AllocatorFailure |
Failed to allocate the copy buffer server-side |
ConversionFailure |
Failed to convert the input buffer to the required data type |
NoVariable |
No variable in the given scope exists with the provided name |
ResetCopyBuffer |
The copy buffer used for constant sets was cleared |