DebugMCP accepts complex GDB expressions but returns empty output for C struct/array inspection
Summary
In embedded C/C++ debugging, DebugMCP can successfully start a debug session, hit breakpoints, and read simple registers/scalars, but it does not reliably surface readable output for complex C/GDB expressions involving structs, arrays, byte buffers, and typed address casts.
The main failure mode is not expression parsing. The command appears to execute successfully, but the returned result contains resultClass: done with empty output.
Environment
- Target: Cortex-M embedded firmware
- VS Code debug adapter: Cortex-Debug
- Session type: Cortex-Debug-backed GDB session inside VS Code
- Debug server: JLink GDB Server
- Debugger:
arm-none-eabi-gdb
- DebugMCP used through VS Code
Repro
At a halted frame in C code, with a local variable like:
ARM_ETH_MAC_ADDR pxMAC_ADDR = { 0 };
and with a known address like 0x2001d17c, try the following through DebugMCP evaluate_expression:
p pxMAC_ADDR
p *(ARM_ETH_MAC_ADDR *)0x2001d17c
print/x pxMAC_ADDR.b[0]
x/6bx &pxMAC_ADDR.b[0]
Actual behavior
The expressions are accepted and do not report parse errors, but the returned result is often effectively empty, for example:
resultClass: done
output: ""
Similarly, local variable inspection can show that a variable exists, but only as a collapsed summary:
pxMAC_ADDR: {...} (ARM_ETH_MAC_ADDR)
without exposing the struct fields or byte array contents.
Expected behavior
DebugMCP should return the actual textual output produced by GDB for these expressions, for example:
{b = {0x46, 0x29, 0x04, 0xb4, 0x78, 0xd8}}
or:
0x2001d17c: 0x46 0x29 0x04 0xb4 0x78 0xd8
For variable inspection, structs and arrays should be expandable instead of only returning {...}.
Control comparison
Running the same commands in external arm-none-eabi-gdb against the same halted target works correctly and prints valid output, for example:
$1 = {b = {0x46, 0x29, 0x4, 0xb4, 0x78, 0xd8}}
0x2001d17c: 0x46 0x29 0x04 0xb4 0x78 0xd8
Simple register reads also work correctly through the same setup, for example:
info registers sp
p/x $sp
returns:
sp 0x2001d170 0x2001d170
$1 = 0x2001d170
This suggests the problem is not basic debugger connectivity, but specifically how DebugMCP captures and surfaces complex C/C++ value output.
Suspected root cause
Possible causes:
evaluate_expression forwards commands to GDB but does not fully capture console/text output.
get_variables_values only returns summarized values and does not recursively expand structs/arrays.
- Complex C/C++ debug value rendering is incomplete compared to scalar/register handling.
Why this matters
This makes DebugMCP much less useful in common embedded debugging scenarios where the important runtime data is stored in:
- structs
- byte arrays
- packet headers
- register blocks
- typed memory views
Requested improvement
- Make
evaluate_expression reliably return GDB text output for commands like p, print, p/x, and x/....
- Make
get_variables_values expand struct fields and array elements.
- Distinguish between:
- command succeeded and produced no output
- command succeeded but output was not captured
- command failed
Minimal acceptance criteria
evaluate_expression("p var") returns printed text for struct values.
evaluate_expression("x/6bx addr") returns byte-dump output.
- Typed address-cast expressions such as
p *(ARM_ETH_MAC_ADDR *)0x2001d17c return readable struct contents.
- Structs and arrays are expandable in variable inspection.
DebugMCP accepts complex GDB expressions but returns empty output for C struct/array inspection
Summary
In embedded C/C++ debugging, DebugMCP can successfully start a debug session, hit breakpoints, and read simple registers/scalars, but it does not reliably surface readable output for complex C/GDB expressions involving structs, arrays, byte buffers, and typed address casts.
The main failure mode is not expression parsing. The command appears to execute successfully, but the returned result contains
resultClass: donewith emptyoutput.Environment
arm-none-eabi-gdbRepro
At a halted frame in C code, with a local variable like:
and with a known address like
0x2001d17c, try the following through DebugMCPevaluate_expression:Actual behavior
The expressions are accepted and do not report parse errors, but the returned result is often effectively empty, for example:
Similarly, local variable inspection can show that a variable exists, but only as a collapsed summary:
without exposing the struct fields or byte array contents.
Expected behavior
DebugMCP should return the actual textual output produced by GDB for these expressions, for example:
or:
For variable inspection, structs and arrays should be expandable instead of only returning
{...}.Control comparison
Running the same commands in external
arm-none-eabi-gdbagainst the same halted target works correctly and prints valid output, for example:Simple register reads also work correctly through the same setup, for example:
returns:
This suggests the problem is not basic debugger connectivity, but specifically how DebugMCP captures and surfaces complex C/C++ value output.
Suspected root cause
Possible causes:
evaluate_expressionforwards commands to GDB but does not fully capture console/text output.get_variables_valuesonly returns summarized values and does not recursively expand structs/arrays.Why this matters
This makes DebugMCP much less useful in common embedded debugging scenarios where the important runtime data is stored in:
Requested improvement
evaluate_expressionreliably return GDB text output for commands likep,print,p/x, andx/....get_variables_valuesexpand struct fields and array elements.Minimal acceptance criteria
evaluate_expression("p var")returns printed text for struct values.evaluate_expression("x/6bx addr")returns byte-dump output.p *(ARM_ETH_MAC_ADDR *)0x2001d17creturn readable struct contents.