NationalSecurityAgency/ghidra · error · Exception

Mismatch on frame

Error message

Mismatch on frame

What it means

Raised as a bare Exception by write_reg() when the frame resolved from the TraceObject (f.FrameNumber) does not equal util.selected_frame(). DbgEng register writes apply to the currently selected stack frame, so writing to a non-selected frame is rejected to avoid corrupting the wrong context.

Source

Thrown at Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/methods.py:858


@REGISTRY.method()
@util.dbg.eng_thread
def write_mem(process: Process, address: Address, data: bytes) -> None:
    """Write memory."""
    nproc = find_proc_by_obj(process)
    offset = process.trace.extra.require_mm().map_back(nproc, address)
    dbg().write(offset, data)


@REGISTRY.method()
@util.dbg.eng_thread
def write_reg(frame: StackFrame, name: str, value: bytes) -> None:
    """Write a register."""
    f = find_frame_by_obj(frame)
    current = util.selected_frame()
    if f.FrameNumber != current:
        raise Exception("Mismatch on frame")
    nproc = util.selected_process()
    trace: Trace[commands.Extra] = frame.trace
    rv = trace.extra.require_rm().map_value_back(nproc, name, value)
    rval = int.from_bytes(rv.value, signed=False)
    dbg().reg._set_register(name, rval)


@REGISTRY.method(display='Refresh Events (custom)', condition=util.dbg.IS_TRACE)
@util.dbg.eng_thread
def refresh_trace_events_custom(node: State,
                                cmd: Annotated[str, ParamDesc(display='Cmd')],
                                prefix: Annotated[str, ParamDesc(display='Prefix')] = "dx -r2 @$cursession.TTD") -> None:
    """Parse TTD objects generated from a LINQ command."""
    with commands.open_tracked_tx('Put Events (custom)'):
        commands.ghidra_trace_put_trace_events_custom(prefix, cmd)


@REGISTRY.method(action='add_handler', display='Add Handler')

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Before writing, select the target frame in DbgEng so util.selected_frame() == f.FrameNumber.
  2. Guard the call: compare util.selected_frame() to the desired FrameNumber and either select it or refuse with a clear message.
  3. Refresh the stack trace and re-resolve the frame object so FrameNumber is current.

Example fix

// before
def write_reg(frame, name, value):
    f = find_frame_by_obj(frame)
    if f.FrameNumber != util.selected_frame():
        raise Exception("Mismatch on frame")
// after
f = find_frame_by_obj(frame)
if f.FrameNumber != util.selected_frame():
    util.select_frame(f.FrameNumber)  # or surface 'select frame first'
dbg().reg._set_register(name, rval)
Defensive patterns

Strategy: validation

Validate before calling

f = find_frame_by_obj(frame)
if f.FrameNumber != util.selected_frame():
    raise RuntimeError(f'frame {f.FrameNumber} is not selected ({util.selected_frame()}); select it first')

Type guard

null

Try / catch

try:
    write_reg(frame, name, value)
except Exception as e:
    if 'Mismatch on frame' in str(e):
        log.warning('register write refused; select frame %s first', frame)
    else:
        raise

Prevention

When it happens

Trigger: Issuing a register write targeting a stack frame that is not the engine's currently selected frame; the UI/model selected a non-top frame and dispatched write_reg against it.

Common situations: User selects a deeper stack frame in the Ghidra UI then tries to edit a register; the target resumed and the selected frame changed underneath the stale FrameNumber.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/6a3fb4f8cc21ec03. Report an issue: GitHub.