Browse documentation
DocsExtensionsV1

Debug

These methods require a live machine. A missing session returns -32000 with VM "<id>" is not running. A session with no machine returns the *-refused:no-machine string for that call.

Addresses may be a JSON number or a hex string (16 or "0x10"). Memory bytes on write are standard base64 or an array of 0–255 integers. Reads return bytes as a JSON array of integers: that is how Vec<u8> serializes.

Caps: a memory read or write longer than 65536 bytes returns memory-read-too-large:<n> / memory-write-too-large:<n>. Disassemble counts are clamped to 1..=64.

debuggerStatus

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1" }
{
  "runState": "paused",
  "activeBackend": "software-interpreter",
  "accelerated": false,
  "canStep": true,
  "canChangePace": true,
  "canForceSoftware": false,
  "softwareForced": false,
  "pace": "full",
  "lastStepWasSoftware": false,
  "stepRefusal": null,
  "vcpuIds": [0]
}

pace is instruction, slow, or full. canStep is true only when runState is paused and a machine is attached. canForceSoftware is true when a hardware backend is active and software has not already been forced.

step

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1", "count": 1 }

count defaults to 1. The VM must be paused. Otherwise -32000 with step-refused:not-paused. Result is { "status": <debuggerStatus> }.

setSoftwarePace

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1", "pace": "instruction" }

Unknown strings become full (pace_code defaults to 0). Result is a DebuggerStatus.

forceSoftwareExecution

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1" }

Result is a DebuggerStatus with softwareForced: true after a successful force.

readMemory / writeMemory

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "address": "0x1000",
  "length": 4,
  "space": "physical",
  "vcpu": 0
}

space "virtual" walks the guest page tables for that vCPU. Any other string is physical.

Physical read of four bytes at 0x1000:

{
  "address": "0x1000",
  "physical": "0x1000",
  "bytes": [18, 52, 86, 120],
  "space": "physical"
}

address / physical use Rust's {:#x} (hex_addr), so they are not zero-padded.

Virtual read includes a translation (regime is ttbr0, ttbr1, or physical). This is the object read_virtual returns in the EL2/TTBR1 unit test (va 0xffffff8000200000 -> pa 0x400000, payload de ad be ef):

{
  "address": "0xffffff8000200000",
  "physical": "0x400000",
  "bytes": [222, 173, 190, 239],
  "space": "virtual",
  "translation": {
    "va": "0xffffff8000200000",
    "pa": "0x400000",
    "regime": "ttbr1"
  }
}

Write uses bytes instead of length and returns the same MemoryRead after the store. Empty writes return memory-write-refused:empty.

snapshotRegisters

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1" }

Result is an array of VcpuRegisterSnapshot. A vCPU that missed the 1s window stays in the list with snapshot: null:

[
  {
    "vcpu": 0,
    "snapshot": {
      "arch": "aarch64",
      "groups": [
        {
          "title": "General Purpose",
          "registers": [
            { "name": "X0", "value": "0x0000000000000001" },
            { "name": "XZR", "value": "0x0000000000000000" },
            { "name": "SP", "value": "0x0000000000000000" },
            { "name": "PC", "value": "0x0000000000080000" }
          ]
        },
        {
          "title": "PSTATE",
          "registers": [
            { "name": "N", "value": "false" },
            { "name": "EL", "value": "EL1" },
            { "name": "BTYPE", "value": "0b00" }
          ]
        }
      ]
    }
  },
  { "vcpu": 7, "snapshot": null }
]

The { "vcpu": 7, "snapshot": null } row is the exact encoding the introspection unit test asserts. AArch64 groups, in order: General Purpose, PSTATE, SIMD and Floating Point, System Registers, Timer Registers, GL1 Registers, Execution State, AMX X Rows, AMX Y Rows, AMX Z Rows. Register values in those groups are uppercase hex (0x plus 16 digits for a u64). x86_64 groups: General Purpose, Segments, Control Registers, Debug Registers, Model Specific Registers, Mask Registers, Vector Registers.

writeRegister

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "vcpu": 0,
  "name": "X0",
  "value": "0x1"
}

Result is one RegisterSnapshot (not the vCPU array). Missing vCPU: register-write-refused:no-vcpu:<id>.

translateAddress

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "vcpu": 0,
  "va": "0xffffff8000200000"
}
{
  "va": "0xffffff8000200000",
  "pa": "0x400000",
  "regime": "ttbr1"
}

disassemble

AArch64 NOP (0xD503201F) at address 0, from disassembles_aarch64_nop:

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "vcpu": 0,
  "address": 0,
  "count": 1
}
[
  {
    "address": "0x0",
    "bytes": "d503201f",
    "text": "nop",
    "current": false
  }
]

x86 NOP (0x90) at address 0, from disassembles_x86_nop: bytes is "90", address is "0x0", text contains nop. current is true when the line address equals PC or RIP. symbol and symbolOffset are omitted when unset. text is the decoder Display / Debug string; the tests only assert it contains nop.

Breakpoints

listBreakpoints:

{ "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1" }
[
  {
    "id": 1,
    "va": "0x80000",
    "vcpu": null,
    "enabled": true
  }
]

addBreakpoint:

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "va": "0x80000",
  "vcpu": null
}

Returns the same StudioBreakpoint object with enabled: true. vcpu omitted or null is every vCPU.

removeBreakpoint:

{
  "vmId": "f1e6a94c-6ee2-4c9b-8a44-9be7b2ca6cf1",
  "id": 1
}

Result is JSON null. The host does not return the inner bool.

14 documentation articles available.