NationalSecurityAgency/ghidra · error · PcodeExecutionException
Cannot get stack change for indirect call
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.
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
- Callee at is not a function.
- Cannot evaluate unique $U
- Cannot make taint concrete
- Cannot make Taint concrete
- Encountered an unimplemented instruction at
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/4559eb5552831e32.
Report an issue: GitHub.
Appendix: 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)