Skip to content

J-K-GO/JKDBG

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build & Run JKDBG Plugin/GUI with QEMU

This guide is written so a first-time user can clone QEMU and JKDBG, copy JKDBG into contrib/plugins, build, and run.

Overview

JKDBG is a comprehensive debugging and monitoring toolkit for QEMU virtual machines, designed to streamline VM development, kernel debugging, and system analysis workflows. It bridges the gap between QEMU's powerful emulation capabilities and user-friendly debugging interfaces by providing an integrated GUI, real-time memory monitoring, and enhanced GDB integration.

Why JKDBG?

JKDBG is a GUI-based time-travel debugger capable of virtual hardware debugging. It constructs an execution timeline through high-speed snapshots and provides CPU-centric debugging features such as register history tracking and classification by customizing GDB. It also offers real-time inspection and modification of the virtual machine’s entire physical memory, along with MMU-aware highlighting for intuitive visualization. These capabilities significantly enhance debugging accuracy and efficiency by enabling stable reproduction of nondeterministic errors that occur in kernel and driver environments, and by allowing developers to understand the global system state at a glance. In particular, the snapshot-based timeline can restore the system to any exact moment, allowing repeated root-cause analysis, while the register history and MMU visualization help clarify complex execution flows and memory-mapping structures. Compared to traditional console-based debugging, JKDBG greatly simplifies the analysis process and provides a safe, VM-isolated environment for experimentation, making it highly suitable for iterative debugging and advanced systems research.

Key Features

  • Integrated GUI Interface: Auto-launching Qt-based GUI that connects to QEMU's QMP, GDB, and VNC interfaces, providing unified control and visualization
  • Real-time Memory Monitoring: Continuous physical memory dumping with configurable intervals, supporting both file output and POSIX shared memory for low-latency analysis
  • Dirty Page Tracking: Efficient dirty page monitoring via message queues, enabling focused analysis of memory modifications during VM execution
  • Enhanced GDB Experience: Python plugin with syntax-highlighted disassembly, color-coded register views, and comprehensive register history tracking
  • Seamless Integration: Designed to work within QEMU's plugin architecture, requiring minimal configuration while offering extensive customization options

Use Cases

JKDBG is particularly valuable for:

  • Embedded Systems Development: Debug ARM/RISC-V/MIPS kernels and bare-metal applications with full register and memory visibility
  • Operating System Development: Track kernel behavior, memory allocation patterns, and page fault handling in real-time
  • Security Research: Monitor memory modifications, analyze exploit behavior, and trace execution flow through vulnerable code paths
  • Reverse Engineering: Capture and analyze memory snapshots at precise execution points with coordinated GDB breakpoints
  • Educational Purposes: Learn system internals with enhanced visibility into CPU state, memory layout, and execution flow

What these plugins do

  • JKDBG plugin (libjkdbg_plugin.so): boots a helper GUI (qt-vm-launcher), passes QMP/GDB/VNC info, and keeps a helper process alive for debugging/monitoring.
  • Physmem plugin (libphysmem.so): periodically dumps guest physical memory to file or POSIX shared memory; can signal via POSIX message queue.
  • Dirtypages plugin (libdirtypages.so): publishes dirty-page information via POSIX message queue for external consumers.

Prerequisites

  • Qt ≥ 6.2 (Widgets, Network) — e.g. /home/<user>/Qt/6.7.3/gcc_64
  • GLib 2.x dev (libglib2.0-dev)
  • libvncclient dev (libvncserver-dev)
  • CMake ≥ 3.16, Ninja (recommended) or Make, gcc/clang

Debian/Ubuntu install example

sudo apt-get update
sudo apt-get install build-essential ninja-build cmake pkg-config \
    libglib2.0-dev libvncserver-dev qt6-base-dev qt6-base-dev-tools \
    qt6-tools-dev qt6-tools-dev-tools

Qt installation notes

  • If you use the Qt online/offline installer, install Qt 6.x (e.g. 6.7.3) and set CMAKE_PREFIX_PATH to the kit path, e.g. /home/<user>/Qt/6.7.3/gcc_64.
  • On distros without recent Qt packages, download the official Qt installer from https://www.qt.io/download-qt-installer, install desktop GCC kit, and export:
    export CMAKE_PREFIX_PATH=/home/<user>/Qt/6.7.3/gcc_64
  • Ensure qmake6/qtpaths6 (or Qt6 cmake config files) are discoverable via CMAKE_PREFIX_PATH.

1) Get sources

# QEMU
git clone https://github.com/qemu/qemu.git ~/qemu-10.1.2

# JKDBG (this repo)
git clone <JKDBG_REPO_URL> ~/JKDBG

2) Copy JKDBG into QEMU contrib/plugins

QEMU_ROOT=~/qemu-10.1.2
JKDBG_DIR=~/JKDBG

# Copy all plugin/GUI sources into contrib/plugins
cd $JKDBG_DIR
cp -r GUI_plugins/ "$QEMU_ROOT/contrib/plugins/"
cp dirtypages.c jkdbg_plugin.c physmem.c "$QEMU_ROOT/contrib/plugins/"
  • After copying, check the changes with cd "$QEMU_ROOT" && git status.
  • The GUI CMakeLists should be configured to use the contrib/plugins/... path.

3) Configure QEMU (once)

cd "$QEMU_ROOT"
./configure --enable-plugins   # add --target-list=... if needed
  • QEMU uses Meson/Ninja under the hood. ./configure writes the Meson build dir ($QEMU_ROOT/build) and build graph.
  • For QEMU 10.1.3+, add plugins to meson.build in $QEMU_ROOT/contrib/plugins.
  • If you change contrib/plugins/meson.build (e.g., add a plugin), rerun either:
    • ./configure --enable-plugins (recreates Meson setup), or
    • meson setup build --reconfigure (from $QEMU_ROOT) to refresh the graph. Then rerun ninja -C build ….

4) Build GUI (bundled qtermwidget)

Assuming GUI lives at contrib/plugins/GUI_plugins:

cmake -S "$QEMU_ROOT/contrib/plugins/GUI_plugins" \
      -B "$QEMU_ROOT/build/GUI_plugins" \
      -DCMAKE_PREFIX_PATH=/home/<user>/Qt/<version>/gcc_64
cmake --build "$QEMU_ROOT/build/GUI_plugins"
# Example output: $QEMU_ROOT/build/GUI_plugins/qt-vm-launcher

5) Build plugin (Meson/Ninja)

ninja -C "$QEMU_ROOT/build" contrib/plugins/libjkdbg_plugin.so
# Output: $QEMU_ROOT/build/contrib/plugins/libjkdbg_plugin.so
  • To also build the physmem/dirtypages sample plugins (if needed):
    ninja -C "$QEMU_ROOT/build" contrib/plugins/libphysmem.so
    ninja -C "$QEMU_ROOT/build" contrib/plugins/libdirtypages.so
    The sources physmem.c and dirtypages.c are copied into contrib/plugins/ by the rsync step above.

If the target is missing: add to contrib/plugins/meson.build

In contrib/plugins/meson.build, append your plugins to the list so Meson creates the targets:

contrib_plugins += ['jkdbg_plugin', 'physmem', 'dirtypages']
if host_os != 'windows'
  contrib_plugins += 'lockstep'
endif
  • File names should match <name>.c (e.g., jkdbg_plugin.c, physmem.c, dirtypages.c in contrib/plugins/).
  • After editing meson.build, rerun configure to refresh the build graph:
cd "$QEMU_ROOT"
./configure --enable-plugins

Then rerun the ninja command above.

To confirm targets are visible in the build graph:

ninja -C "$QEMU_ROOT/build" -t targets | grep jkdbg
ninja -C "$QEMU_ROOT/build" -t targets | grep physmem

6) Run example (templated)

cd "$QEMU_ROOT"
export JKDBG_QMP_PORT=4444
export JKDBG_GDB_PORT=1234
export JKDBG_VNC_DISPLAY=<vnc_display>   # e.g. 3
# If you want to pin the GUI path:
# export JKDBG_GUI_PATH="$QEMU_ROOT/build/GUI-plugins/qt-vm-launcher"

./build/qemu-system-<arch> \
  -L "$QEMU_ROOT/pc-bios" \
  -M <machine> \
  -m <mem_size> \
  -kernel <kernel_image> \
  -drive file=<disk_image>,format=qcow2,if=sd \
  -display none \
  -vnc :${JKDBG_VNC_DISPLAY} -k en-us \
  -serial vc \
  -monitor telnet:127.0.0.1:5555,server,nowait \
  -qmp tcp:localhost:${JKDBG_QMP_PORT},server=on,wait=off \
  -S \
  -gdb tcp:localhost:${JKDBG_GDB_PORT},ipv4 \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libdirtypages.so",mq_name=/qemu-physmem-mq \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libphysmem.so",size=1M,out=shm,shm_name=/qemu-physmem,chunk=64K,interval_ms=1000,mq=1 \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libjkdbg_plugin.so",gui=1,vnc=${JKDBG_VNC_DISPLAY}
  • Fill <arch>/<machine>/<mem_size>/<kernel_image>/<disk_image>/<vnc_display> to match your target (e.g. arm/realview-pb-a8/1G/…).
  • Suppress audio warnings: -audio none or -audiodev none,id=noaudio -machine audiodev=noaudio.
  • Keymaps/BIOS: -L "$QEMU_ROOT/pc-bios" to read from the build tree.

GUI lookup order (plugin)

  1. JKDBG_GUI_PATH env
  2. <plugin_dir>/jkdbg-gui
  3. <plugin_dir>/qt-vm-launcher
  4. <plugin_dir>/../qt-vm-launcher
  5. <plugin_dir>/plugins/qt-vm-launcher
  6. <plugin_dir>/plugins/GUI_plugins/qt-vm-launcher
  7. <plugin_dir>/plugins/GUI_plugins/build/qt-vm-launcher

Qt compatibility

  • Tested with Qt ≥ 6.2; built on Qt 6.7.x.
  • Qt5 is not recommended (CMake not set up for it).

License notices

  • libvncclient (LibVNCServer): GPL-2.0-or-later. Linking (static/dynamic) triggers GPL obligations (source, notices, etc.).
  • qtermwidget: GPL-2.0-or-later. Some files are LGPL-2.1+/BSD-3-Clause, but the library is distributed as GPL-2.0-or-later, so GPL obligations propagate.
  • Qt 6: mostly LGPL-3.0-or-later (some modules GPL/commercial). With LGPL, ensure dynamic linking, notices, and user replacement rights where applicable.
  • GLib: LGPL-2.1-or-later. Follow LGPL requirements when dynamically linked.

Summary: libvncclient and qtermwidget are GPL-2.0-or-later, so any binary linking against them (GUI or plugin) must satisfy GPL duties (provide source, preserve notices, same license on redistribution). Even for internal use, review the terms.

Per-file/component license summary

  • JKDBG plugin sources (jkdbg_plugin.c, physmem.c, dirtypages.c, etc., yielding contrib/plugins/libjkdbg_plugin.so): GPL-2.0-only (project authors). GPL obligations apply when distributing, due to libvncclient/qtermwidget.
  • GUI sources (contrib/plugins/GUI_plugins *.cpp, *.h, resources, etc.): should be shipped under a GPL-compatible license; GPL duties apply because they link qtermwidget/libvncclient.
  • Bundled qtermwidget (contrib/plugins/GUI_plugins/lib): GPL-2.0-or-later (contains some LGPL-2.1+/BSD-3-Clause files, but overall GPL-2.0-or-later).
  • External libs:
    • libvncclient (LibVNCServer): GPL-2.0-or-later
    • Qt 6 modules (Widgets/Network, etc.): mostly LGPL-3.0-or-later (some GPL/commercial)
    • GLib: LGPL-2.1-or-later

GPL compliance and license files

  • Project-authored plugin code is GPL-2.0-only; keep source and copyright/license notices.
  • Because we link to GPL libs (libvncclient, qtermwidget), distributing the plugin/GUI requires GPL compliance (source, notices, same license).
  • Include LICENSE (GPL-2.0 text) at repo root and copies of third-party licenses (libvncclient, qtermwidget, Qt, GLib). Add license notices to distributions.

Distribution info

  • Final release year: 2025
  • Distributor: Team J.K.GO

Plugin usage and options

Load plugins with -plugin <path>,key=value,... on the QEMU command line. Below are the main plugins in this tree and their knobs.

JKDBG plugin (libjkdbg_plugin.so)

  • Purpose: auto-launch the Qt GUI (qt-vm-launcher) and pass QMP/GDB/VNC info to it.
  • Options:
    • gui=1|0 — force enable/disable GUI launch. If omitted, behavior follows env/prompt logic (and JKDBG_AUTO_LAUNCH).
    • vnc=<display> — pass VNC display (e.g. vnc=3 for :3) to the GUI.
  • Environment variables (override or supply defaults):
    • JKDBG_GUI_PATH — absolute path to the GUI binary (otherwise searched in plugin-relative locations).
    • JKDBG_VNC_DISPLAY — VNC display number if not provided via vnc=.
    • JKDBG_QMP_PORT — QMP port (default 4444).
    • JKDBG_GDB_PORT — GDB port (default 1234).
    • JKDBG_AUTO_LAUNCH1/yes/true auto-launches GUI, 0/no/false disables; if unset, may prompt.
  • Search order for GUI: JKDBG_GUI_PATH, then relative to the plugin: jkdbg-gui, qt-vm-launcher, ../qt-vm-launcher, plugins/qt-vm-launcher, plugins/GUI_plugins/qt-vm-launcher, plugins/GUI_plugins/build/qt-vm-launcher.

Physmem plugin (libphysmem.so from physmem.c)

  • Purpose: dump guest physical memory to file or shared memory at intervals; optional message queue coordination.
  • Options:
    • size=<bytes> — total capture size (e.g. 1M). Default: guest RAM size (if unset) or plugin default.
    • out=<path|shm> — destination; shm uses POSIX shared memory, otherwise a file path.
    • shm_name=<name> — POSIX shm name when out=shm (e.g. /qemu-physmem).
    • chunk=<bytes> — write chunk size (e.g. 64K). Smaller chunks reduce latency but increase overhead.
    • interval_ms=<ms> — sampling interval (e.g. 1000 for 1s). Lower values sample more frequently.
    • mq=1|0 — enable/disable POSIX message queue notifications to coordinate with consumers.

Dirtypages plugin (libdirtypages.so from dirtypages.c)

  • Purpose: report dirty pages via message queue.
  • Options:
    • mq_name=<name> — POSIX message queue name (e.g. /qemu-physmem-mq). The consumer should listen on the same queue.

Example (templated):

./build/qemu-system-<arch> ... \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libdirtypages.so",mq_name=/qemu-physmem-mq \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libphysmem.so",size=1M,out=shm,shm_name=/qemu-physmem,chunk=64K,interval_ms=1000,mq=1 \
  -plugin "$QEMU_ROOT/build/contrib/plugins/libjkdbg_plugin.so",gui=1,vnc=${JKDBG_VNC_DISPLAY}

Gdb plugin (jkdbg.py)

  • This plugin adds GUI-Friendly commands for controlling QENU execution and inspecting register output history.
Command Description Usage
c Continue execution. Used in the GUI to run QEMU. c
Ctrl + C Interrupt execution and break into the debugger. (keyboard interrupt)
jkhist Print register output history collected during the session. jkhist [reg] -n [number]
  • jkhist Options
    • [reg] : Register name to filter history
    • -n [number] : Number of recent outputs to display