NationalSecurityAgency/ghidra · error · UnwindException
Could not find a path from {function} entry to {pc}
Error message
Could not find a path from {function} entry to {pc} What it means
Thrown by UnwindAnalysis.AnalysisForPC.computeUnwindInfo() when getEntryPaths() returns an empty collection — meaning the basic block graph has no path from the function's entry block to the block containing the program counter. The Dijkstra shortest-path search found the PC block is unreachable from entry, making unwind analysis impossible for this PC.
Source
Thrown at Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/UnwindAnalysis.java:454
* <p>
* This strategy does make some assumptions:
* <ul>
* <li>The function returns.</li>
* <li>For every edge in the basic block graph, the stack depth at the end of its source
* block is equal to the stack depth at the start of its destination block.</li>
* <li>The function follows a "sane" convention. While it doesn't have to be any particular
* convention, it does need to restore its saved registers, and those registers should be
* saved to the stack in a straightforward manner.</li>
* </ul>
*
* @return the unwind information
* @throws CancelledException if the monitor cancels the analysis
*/
public UnwindInfo computeUnwindInfo() throws CancelledException {
// TODO: Find out to what other pc values this applies and cache?
Collection<Deque<BlockEdge>> entryPaths = getEntryPaths();
if (entryPaths.isEmpty()) {
throw new UnwindException(
"Could not find a path from " + function + " entry to " + pc);
}
Collection<Deque<BlockEdge>> exitsPaths = getExitsPaths();
if (exitsPaths.isEmpty()) {
warnings.add(new NoReturnPathStackUnwindWarning(pc));
}
SymPcodeExecutorState lastSuccessfulEntryState = null;
Exception lastError = null;
// TODO: Proper exceptions for useless results
for (Deque<BlockEdge> entryPath : entryPaths) {
SymPcodeExecutorState entryState;
try {
entryState = executeToPc(entryPath);
}
catch (Exception e) {
lastError = e;
continue;
}View on GitHub (pinned to d5f144c24d)
Solutions
- Re-disassemble the function: clear the code units and re-create the function to rebuild the block graph.
- Fix switch table recovery so indirect jumps resolve their targets and connect the CFG edges.
- Manually add missing references or fix disassembly at suspicious instruction boundaries.
- Run the 'Decompiler Switch Analysis' analyzer to recover jump tables that create CFG connectivity.
- If the function is genuinely noreturn or has complex control flow, consider manual unwind specification.
Example fix
// No code fix; the issue is in static analysis: // 1. Delete the function at the address, re-disassemble, recreate function. // 2. Run Decompiler Switch Analysis on the program.
Defensive patterns
Strategy: try-catch
Validate before calling
// No simple pre-check; the path computation is the check itself. // You can verify the block graph is connected before full analysis: BlockGraph graph = new BlockGraph(monitor); // check reachability of the PC block from entry before full computeUnwindInfo()
Type guard
// No type guard; this is a runtime analysis condition. // The CFG connectivity is only known after block model construction.
Try / catch
try {
unwindInfo = analysisForPC.computeUnwindInfo();
} catch (UnwindException e) {
if (e.getMessage().startsWith("Could not find a path")) {
// re-disassemble the function, run switch analysis, then retry
} else { throw e; }
} Prevention
- Run the Decompiler Switch Analysis analyzer to recover jump table edges.
- Fix disassembly errors (wrong instruction boundaries) before unwinding.
- Re-create functions over suspect code regions to rebuild the block graph.
- Check for obfuscated control flow that breaks standard CFG construction.
When it happens
Trigger: After constructing the BlockGraph and finding the PC's block vertex via blockModel.getCodeBlocksContaining(pc), getEntryPaths() uses DijkstraShortestPathsAlgorithm to find paths from the function entry block to the PC block, and none exist. This happens when the control-flow graph is disconnected — the PC block is in a different SCC or unreachable due to incorrect disassembly, or the block model fragmented the code incorrectly.
Common situations: The disassembly has errors (wrong instruction boundaries) creating spurious blocks. A switch/jump table wasn't recovered, so edges into the PC's block are missing. The function was created over data or mixed code/data. Obfuscated code with indirect jumps that Ghidra didn't resolve. Compiler-generated code with unusual control flow (exception handlers, computed gotos).
Related errors
- No function contains {pc}
- The function for the frame is no longer present in the mappe
- Cannot find static program for frame ({pc}={pcVal})
- Unsupported value: {}
- Invalid value for {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/0d24d7dd64f72d51.
Report an issue: GitHub.