NationalSecurityAgency/ghidra · error · RuntimeError

Usage: ghidra trace putval EXPRESSION [PAGES]

Error message

Usage: ghidra trace putval EXPRESSION [PAGES]

What it means

Usage error raised by ghidra_trace_putval when the token count is not 1 or 2. putval records the bytes of an EXPRESSION's value into the trace, with an optional second PAGES flag. NOTE: the source has a latent bug on line 764 (pages = util.get_eval(args[2]) while only args[0..1] exist), so the 2-arg path itself can IndexError before this message is reached in some builds.

Source

Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py:766

    or its address is not in memory, an error results.

    Please note, register and value aliases, e.g., '$pc' or '$1' may be assigned
    to a temporary memory address by LLDB. Thus, a command like

       ghidra trace putval $1

    may result in undefined behavior.
    """

    args = shlex.split(command)
    if len(args) == 1:
        expression = args[0]
        pages = True
    elif len(args) == 2:
        expression = args[0]
        pages = (util.get_eval(args[2]).unsigned != 0)
    else:
        raise RuntimeError("Usage: ghidra trace putval EXPRESSION [PAGES]")

    STATE.require_tx()
    try:
        value = util.get_eval(expression)
        address = value.addr
    except BaseException as e:
        raise RuntimeError(f"Could not evaluate {expression}: {e}")
    if not address.IsValid():
        raise RuntimeError(f"Expression {expression} does not have an address")
    start = int(address)
    end = start + start + value.size
    return put_bytes(start, end, result, pages)


def putmem_state(address: str, length: str, state: str,
                 pages: bool = True) -> None:
    trace = STATE.require_trace()
    trace.validate_state(state)

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Pass exactly one token (EXPRESSION) or two tokens (EXPRESSION PAGES).
  2. For PAGES, pass a positional 0/1 expression like '1' or '0', not a flag.
  3. If the 2-arg form crashes with IndexError on args[2], patch commands.py line 764 to use args[1] (this is a code bug, not user error).

Example fix

// before
ghidra trace putval myvar --pages
// after
ghidra trace putval myvar 1
Defensive patterns

Strategy: validation

Validate before calling

import shlex

def validate_putval(command: str) -> None:
    n = len(shlex.split(command))
    if n not in (1, 2):
        raise ValueError('ghidra trace putval needs EXPRESSION [PAGES]')
    # NOTE: even when n==2, source reads args[2] (a bug); prefer n==1 to be safe.
    if n == 2:
        import warnings
        warnings.warn('putval 2-arg form has an args[2] indexing bug; pass EXPRESSION only.')

Try / catch

try:
    ghidra_trace_putval(debugger, command, result, internal_dict)
except (RuntimeError, IndexError) as e:
    result.SetError(f'putval failed ({type(e).__name__}): {e}')

Prevention

When it happens

Trigger: Calling 'ghidra trace putval' with zero tokens or 3+ tokens. Separately, a call with exactly 2 tokens may instead throw IndexError at args[2] because the code reads the wrong array slot for PAGES.

Common situations: User adds a --pages flag (unsupported); user passes both a value and a length; user wraps the expression in extra quotes producing unexpected splits.

Related errors


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