Skip to content

GrammaTech/halucinator-vscode

Repository files navigation

HALucinator VSCode Extensions

VSCode tooling for HALucinator firmware emulation — config editing, DAP debugging, and project management.

Extension in action

Published at: https://github.com/GrammaTech/halucinator-vscode

Branches

Branch Purpose
main Active development. Unified extension — both DAP and GDB debug backends, selectable per-project.
archive/gtirb-main Frozen snapshot of the pre-unified extension with GTIRB support.
archive/gview-only Frozen snapshot of the DAP-only variant (no GTIRB). Superseded by main.
archive/gdb-debug-mode Frozen snapshot of the GDB-only variant. Superseded by main.

archive/* branches are reference-only and don't receive updates. The unified extension on main lets you choose DAP or GDB via the halucinator.debugBackend setting or the Debug Backend dropdown in the project editor. You don't need to pick a branch — main is the one to use.

Repository Structure

halucinator-vscode/
├── extensions/
│   ├── halucinator/          # Main extension (config, debug, project, runtime)
│   └── gview-extension/      # Ghidra assembly viewer

Prerequisites

  • VSCode 1.80+
  • Node.js 20+ (for building)
  • HALucinator installed locally (pip install -e src) or available as a Docker image
  • QEMU built for your target architecture (via halucinator's build_qemu.sh)

Building the Extension

cd extensions/halucinator
npm install
npm run build          # Compiles TypeScript + bundles with esbuild

This produces halucinator-vscode-1.0.0.vsix.

Installing in VSCode

# Install the main extension
code --install-extension extensions/halucinator/halucinator-vscode-1.0.0.vsix

# Install required dependency
code --install-extension redhat.vscode-yaml

# Install gview extension (for Ghidra assembly disassembly)
cd extensions/gview-extension
npm install
npx @vscode/vsce package --allow-missing-repository
code --install-extension gview-extension-1.0.0.vsix
cd ../..

Quick Start: STM32 UART Example (Local Mode)

This walkthrough uses the STM32 UART test included in the halucinator repo.

1. Set up halucinator

# Clone and install halucinator (if not already done)
git clone https://github.com/halucinator/halucinator.git
cd halucinator
git submodule update --init --recursive

# Create virtualenv and install
python3 -m venv venv
source venv/bin/activate
pip install -e deps/avatar2/
pip install -r src/requirements.txt
pip install -e src

# Build QEMU (ARM)
./build_qemu.sh arm-softmmu

2. Set the QEMU environment variable

export HALUCINATOR_QEMU_ARM="$(pwd)/deps/build-qemu/arm-softmmu/qemu-system-arm"

3. Open the test project in VSCode

code test/STM32/example/

4. Configure the extension

  1. Open the Command Palette (Ctrl+Shift+P)
  2. Run "HALucinator: Open/Create Project"
  3. In the project editor that opens:
    • Docker Image: Leave empty (we're using local mode)
    • ELF Binary: Click "Browse..." and select Uart_Hyperterminal_IT_O0.elf
    • gview File: Click "Generate" to auto-create from the ELF using Ghidra (~1-2 min) Or click "Browse..." if you already have a .gview file.
    • Configuration Files: Click "Add Config File(s)..." and select all three:
      • Uart_Hyperterminal_IT_O0_config.yaml
      • Uart_Hyperterminal_IT_O0_memory.yaml
      • Uart_Hyperterminal_IT_O0_addrs.yaml
    • Click "Save Project"

This creates a halucinator.json file in the project directory.

5. Check the extension settings (optional)

Open VSCode Settings (Ctrl+,) and search for "halucinator":

  • Mode: auto (default) — automatically detects Docker or local install
  • DAP Port: 34157 (default)

6. Start debugging

In the project editor, click "Start Debugging". This single button:

  1. Launches halucinator with --dap and your config files
  2. Waits for the DAP server on port 34157
  3. Opens the gview disassembly file
  4. Starts the VSCode debug session

The debug toolbar appears — you can step, continue, inspect variables, set breakpoints in the gview assembly.

7. Inspect the HALucinator Intercepts panel

Look at the bottom panel — the "HALucinator" tab shows:

  • Config Files: The three YAML files you loaded
  • Intercepts: All function intercepts (HAL_UART_Init, HAL_Delay, etc.)
  • Add Intercept: Form to add new intercepts with handler class dropdown

8. Interact with the UART peripheral

In a separate terminal, open an interactive UART console using the built-in peripheral tool:

source /path/to/halucinator/venv/bin/activate
hal_dev_uart --id=0x40011000 --newline

This opens a live UART terminal — type input and see firmware responses. The --id is the UART peripheral address from the memory config.

Alternatively, you can script it with Python:

from halucinator.external_devices.ioserver import IOServer
from halucinator.external_devices.uart import UARTPrintServer
import time

io = IOServer(5556, 5555)
uart = UARTPrintServer(io)
io.start()
time.sleep(3)
uart.send_data(0x40013800, '1234567890')
time.sleep(15)
io.shutdown()

Quick Start: Docker Mode

If you're running halucinator inside Docker:

1. Build the Docker image

cd halucinator
docker build -t halucinator:latest .

2. Configure VSCode settings

In VSCode Settings (Ctrl+,), search for "halucinator":

  • Mode: docker
  • Docker Image: halucinator:latest
  • Container Name: halucinator (default)

3. Open your project in VSCode

code /path/to/your/firmware/project/

4. Create a project

  1. Ctrl+Shift+P"HALucinator: Open/Create Project"
  2. Set Docker Image to halucinator:latest
  3. Browse for your ELF binary and config files
  4. Click "Save Project"

5. Start and debug

  1. Ctrl+Shift+P"HALucinator: Start Container" (starts the Docker container)
  2. Ctrl+Shift+H → Opens an interactive shell inside the container
  3. Ctrl+Shift+P"HALucinator: Start Debugger" (launches halucinator with --dap)
  4. Ctrl+Shift+P"Debug with HALucinator" (connects VSCode to the DAP server)

Extension Commands

Command Shortcut Description
HALucinator: Open/Create Project Open the project editor webview
HALucinator: Start Debugger Launch halucinator (Docker or local)
HALucinator: Stop Debugger Stop running halucinator instance
HALucinator: Open Shell Ctrl+Shift+H Open interactive terminal (Docker: shell in container)
HALucinator: Start Container Start the Docker container (Docker mode only)
Debug with HALucinator Connect VSCode debugger to DAP server
HALucinator: Import Config Add existing YAML config files
HALucinator: Create Config Create a new config file from template
HALucinator: Refresh Handler Class List Re-scan for available bp_handler classes
HALucinator: Add Handler Directory Add custom handler search directory (Docker)
HALucinator: Reset Handler Directories Remove all custom handler directories (Docker)
HALucinator: Reload Configuration Reload Docker/tool settings

Extension Settings

Setting Default Description
halucinator.mode auto Runtime mode: auto, docker, or local
halucinator.dockerImage (empty) Docker image name (empty = halucinator:latest)
halucinator.containerName halucinator Docker container name
halucinator.dapPort 34157 Debug Adapter Protocol server port
halucinator.project.fileName halucinator.json Project config file name
halucinator.project.dap.enabled true Pass --dap flag when launching halucinator

Debug Features

When connected to the HALucinator DAP server:

  • Breakpoints: Set in assembly listings (gtgas, gtmips, gview languages)
  • Step/Continue/Pause: Standard debug controls
  • Variable inspection: View registers, stack, and global memory
  • Variable formatting: Right-click variables to change display format (hex, signed, unsigned, arrays, pointers, different encodings)
  • HAL break toggle: Toolbar button to pause/continue on HAL intercepts
  • Memory inspection: Read arbitrary memory addresses

Config File Format

HALucinator uses YAML config files with these sections:

# Machine configuration
machine:
  arch: cortex-m3
  cpu_model: cortex-m3
  entry_addr: 0x08003D49
  init_sp: 0x20014000

# Memory regions
memories:
  flash: { base_addr: 0x8000000, file: firmware.bin, permissions: r-x, size: 0x200000 }
  ram: { base_addr: 0x20000000, size: 0x51000 }

# Function intercepts
intercepts:
  - class: halucinator.bp_handlers.ReturnZero
    function: HAL_Init
    symbol: HAL_Init
  - class: halucinator.bp_handlers.stm32f4.stm32f4_uart.STM32F4UART
    function: HAL_UART_Init
    symbol: HAL_UART_Init

The extension provides YAML schema validation for these files — you'll get autocomplete and error highlighting.

Architecture

VSCode
├── HALucinator Extension (gt-halucinator.halucinator-vscode)
│   ├── Config Editor Panel (bottom panel webview)
│   ├── Project Editor (webview panel)
│   ├── DAP Client ──────────── TCP:34157 ──── HALucinator DAP Server
│   ├── Docker Runner ──────── docker exec ──── Container
│   │   or Local Runner ────── direct exec ──── halucinator CLI
│   ├── Tool Base ──────────── commands ──────── gview-extension
│   └── Handler Autocomplete ── reads ────────── .hal_bp_handlers.json
│
└── gview-extension
    └── GView LSP Server ──── stdio ──────────── Python pygls server

Troubleshooting

"DAP server not reachable on port 34157"

  • Make sure halucinator is running with --dap flag
  • Check that nothing else is using port 34157
  • In Docker mode, ensure --network=host is used

"No config files loaded" in the Intercepts panel

  • Import config files: Ctrl+Shift+P → "HALucinator: Import Config"
  • Or open a project: Ctrl+Shift+P → "HALucinator: Open/Create Project"

Handler autocomplete not working

  • Run Ctrl+Shift+P → "HALucinator: Refresh Handler Class List"
  • Check that .hal_bp_handlers.json exists in your project directory

Docker container won't start

  • Verify the Docker image exists: docker image inspect halucinator:latest
  • Check the container name isn't already in use: docker ps -a

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors