NationalSecurityAgency/ghidra · error · LowlevelError

Unsupported p-code op at {}: {}

Error message

Unsupported p-code op at {}: {}

What it means

Thrown (unchecked LowlevelError) by badOp() as the default case: the op's opcode is neither UNIMPLEMENTED nor one the evaluator's evaluateOp dispatch handles. Unlike the UNIMPLEMENTED case, this is an opcode the emulator simply doesn't support (e.g. exotic p-code ops not yet wired into the evaluator switch).

Source

Thrown at Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/eval/AbstractVarnodeEvaluator.java:428

			default:
				return badOp(op);
		}
	}

	/**
	 * The method invoked when an unrecognized or unsupported operator is encountered
	 * 
	 * @param op the op
	 * @return the value, but this usually throws an exception
	 */
	protected T badOp(PcodeOp op) {
		switch (op.getOpcode()) {
			case PcodeOp.UNIMPLEMENTED:
				throw new LowlevelError(
					"Encountered an unimplemented instruction at " +
						op.getSeqnum().getTarget());
			default:
				throw new LowlevelError(
					"Unsupported p-code op at " + op.getSeqnum().getTarget() + ": " + op);
		}
	}
}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Override evaluateOp in your subclass to add cases for the missing opcode(s) named in the message.
  2. Inspect op.getOpcode() for the failing op and implement/redirect its handling (often return the value of the relevant input or a symbolic result).
  3. Catch LowlevelError and degrade gracefully for unsupported ops if full coverage isn't required.
  4. Track the Ghidra version's PcodeOp constants so newly added opcodes get handlers.

Example fix

// before: default badOp throws on unhandled opcode
T out = evaluator.evaluateOp(program, op, cache);

// after: add the missing case in your subclass's evaluateOp
@Override
protected T evaluateOp(Program p, PcodeOp op, Map<Varnode,T> cache) {
    switch (op.getOpcode()) {
        case PcodeOp.MULTIEQUAL:
            return evaluateVarnode(p, op.getInput(0), cache);
        default:
            return super.evaluateOp(p, op, cache);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check opcode coverage before delegating to the base evaluator
if (!isHandledByEvaluator(op.getOpcode())) {
    // opcode has no case in evaluateOp -> badOp default; add a handler
}

Try / catch

try {
    T out = evaluator.evaluateOp(program, op, cache);
} catch (LowlevelError e) {
    if (e.getMessage().startsWith("Unsupported p-code op")) { /* add handler / degrade */ }
    else throw e;
}

Prevention

When it happens

Trigger: Driving AbstractVarnodeEvaluator (or a subclass) over p-code whose opcode has no case in evaluateOp, so it falls through to badOp's default. Occurs with newer/rarer p-code ops (e.g. newly added ops, or ops your subclass didn't override) on standard instructions.

Common situations: A new Ghidra version adds p-code ops your evaluator subclass doesn't handle; analyzing code that exercises p-code ops (like MULTIEQUAL, INDIRECT, certain CALLOTHER ops) not covered by your override; partial evaluator implementation.

Related errors


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