NationalSecurityAgency/ghidra · error · PcodeExecutionException
Cannot get stack change for indirect call: {op}
Error message
Cannot get stack change for indirect call: {op} What it means
Thrown during symbolic p-code execution of an indirect CALL when no function signature can be determined for the call target AND the default calling convention's extrapop value is UNKNOWN_EXTRAPOP. SymPcodeExecutor.computeStackChangeIndirect() tries to get the signature, falls back to the default convention's extrapop, and if that is also unknown, the stack depth change cannot be computed, halting unwinding.
Source
Thrown at Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/SymPcodeExecutor.java:365
int purge = max == null ? 0 : (int) max.subtract(min);
// AFAIK, this stdcall only applies to x86, so presume return address on stack
return purge + program.getLanguage().getProgramCounter().getNumBytes();
}
/**
* Compute the stack change for an indirect call
*
* @param op the low p-code op
* @return the depth change
*/
protected int computeStackChangeIndirect(PcodeOp op) {
FunctionSignature sig = getSignatureOfIndirectCall(op);
if (sig == null) {
int extrapop = program.getCompilerSpec().getDefaultCallingConvention().getExtrapop();
if (extrapop != PrototypeModel.UNKNOWN_EXTRAPOP) {
return extrapop;
}
throw new PcodeExecutionException("Cannot get stack change for indirect call: " + op);
}
PrototypeModel convention =
program.getCompilerSpec().matchConvention(sig.getCallingConventionName());
if (convention == null) {
warnings.add(new UnspecifiedConventionStackUnwindWarning(null));
convention = program.getCompilerSpec().getDefaultCallingConvention();
}
int extrapop = convention.getExtrapop();
if (extrapop != PrototypeModel.UNKNOWN_EXTRAPOP) {
return extrapop;
}
return computeStdcallExtrapop(convention, sig);
}
/**
* Apply the given stack change to the machine state
*
* <p>View on GitHub (pinned to d5f144c24d)
Solutions
- Analyze the indirect call target so getSignatureOfIndirectCall can resolve a signature (define the target function and its calling convention).
- Set or correct the default calling convention's extrapop in the processor's .cspec file.
- If the target is known, apply the correct function signature so the convention can be matched.
- For custom architectures, ensure the PrototypeModel defines a concrete extrapop value instead of UNKNOWN_EXTRAPOP.
Example fix
// In the .cspec for the language, ensure the default prototype model defines extrapop: // <prototype name="default" ... extrapop="8"> // instead of extrapop="unknown"
Defensive patterns
Strategy: validation
Validate before calling
// Before emulating indirect calls, check if the convention has a known extrapop:
PrototypeModel defaultConv = program.getCompilerSpec().getDefaultCallingConvention();
if (defaultConv.getExtrapop() == PrototypeModel.UNKNOWN_EXTRAPOP) {
// warn: indirect calls with unknown signatures will fail stack change computation
} Type guard
private boolean canComputeIndirectStackChange(Program program) {
return program.getCompilerSpec()
.getDefaultCallingConvention()
.getExtrapop() != PrototypeModel.UNKNOWN_EXTRAPOP;
} Try / catch
try {
executor.execute(op, frame, library);
} catch (PcodeExecutionException e) {
if (e.getMessage().startsWith("Cannot get stack change for indirect call")) {
// fall back to manual stack adjustment or skip frame
} else { throw e; }
} Prevention
- Define function signatures for indirect call targets so signatures can be resolved.
- Ensure the .cspec default prototype model defines a concrete extrapop value.
- Analyze indirect call sites with the decompiler to populate signature information.
- For custom architectures, always set extrapop in the compiler spec.
When it happens
Trigger: computeStackChangeIndirect() calls getSignatureOfIndirectCall(op) which returns null (no signature resolution), then checks program.getCompilerSpec().getDefaultCallingConvention().getExtrapop() which equals PrototypeModel.UNKNOWN_EXTRAPOP (-1). This combination means neither the call site nor the compiler spec provides stack adjustment info.
Common situations: Debugging/emulating code with indirect calls through function pointers or vtables where the target function isn't analyzed. The compiler spec for the processor doesn't define a default extrapop (common in non-x86 architectures or custom language definitions). The calling convention metadata is incomplete for the target platform.
Related errors
- Input %s conflicts: 0x%s != 0x%s
- Timed out reading or writing target
- Error reading or writing target
- Callee at {target} is not a function.
- Issue executing callee fixup:
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/4559eb5552831e32.
Report an issue: GitHub.