NationalSecurityAgency/ghidra · error · IllegalArgumentException
Could not find a register for
Error message
Could not find a register for
What it means
Thrown by PatchStep while serializing a byte-patch into register assignments: for the next patched address 'min' in the register address space, no register was found that starts exactly at 'min', fits within the data length, and is contained in the remaining patched span (the stream over language.getRegisters(min) returned empty after the filters). The patch bytes therefore do not align to any register boundary defined by the language.
Source
Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/time/schedule/PatchStep.java:175
}
protected static void generateRegisterSleigh(List<String> result, Language language,
AddressSpace space, SemisparseByteArray array) {
byte[] data = new byte[8];
MutableULongSpanSet remains = new DefaultULongSpanSet();
remains.addAll(array.getInitialized(0, -1));
while (!remains.isEmpty()) {
ULongSpan bound = remains.bound();
Address min = space.getAddress(bound.min());
Register register = Stream.of(language.getRegisters(min))
.filter(r -> r.getAddress().equals(min))
.filter(r -> r.getNumBytes() <= data.length)
.filter(r -> isContained(r, remains))
.sorted(Comparator.comparing(r -> -r.getNumBytes()))
.findFirst()
.orElse(null);
if (register == null) {
throw new IllegalArgumentException("Could not find a register for " + min);
}
if (register.getBaseRegister().isProgramCounter()) {
register = register.getBaseRegister();
}
int length = register.getNumBytes();
array.getData(register.getOffset(), data, 0, length);
BigInteger value = Utils.bytesToBigInteger(data, length, language.isBigEndian(), false);
if (register.isProgramCounter()) {
result.add(String.format("goto 0x%s", value.toString(16)));
}
else {
result.add(String.format("%s=0x%s", register, value.toString(16)));
}
remains.remove(spanOfRegister(register));
}
}
public static PatchStep parse(long threadKey, String stepSpec) {View on GitHub (pinned to d5f144c24d)
Solutions
- Align the patched range to whole registers (start at a register boundary and span whole register widths).
- Verify the language defines a register at that offset; if not, patch the underlying memory/register space differently.
- When building the PatchStep, decompose arbitrary byte ranges into per-register patches before serialization.
- Catch IllegalArgumentException and report the offending offset 'min' to locate the misaligned patch.
Example fix
// before // patch starts at a sub-offset no register begins at -> 'Could not find a register for 0x..' // after // snap the patch start to the nearest enclosing register's offset Register enc = language.getRegister(new AddressRangeImpl(min, min)); long regOff = enc != null ? enc.getOffset() : min; // build the patch from regOff covering enc.getNumBytes()
Defensive patterns
Strategy: try-catch
Validate before calling
// Before building/serializing a PatchStep, verify each patched span starts on a register:
Register reg = Stream.of(language.getRegisters(addr))
.filter(r -> r.getAddress().equals(addr))
.findFirst().orElse(null);
if (reg == null) { /* re-align the patch to a register boundary */ } Type guard
static boolean alignedToRegister(Language lang, Address addr, int maxBytes) {
return Stream.of(lang.getRegisters(addr))
.anyMatch(r -> r.getAddress().equals(addr) && r.getNumBytes() <= maxBytes);
} Try / catch
try {
patchStep.serialize(language);
} catch (IllegalArgumentException e) {
// e.getMessage() names the misaligned address 'min'; decompose the patch into per-register writes
} Prevention
- Align patched byte ranges to whole registers (register start offset + full width).
- Decompose arbitrary byte patches into per-register patches before serializing.
- Confirm the language defines a register at the patched offset for custom languages.
When it happens
Trigger: Serializing a PatchStep whose patched byte range (in the register address space) does not begin on a register start offset, or covers bytes no single register (within the available length) can represent, e.g. a sub-register slice with no enclosing register, or a patch that straddles register boundaries without covering a whole register.
Common situations: Emulator/tracer writing partial-register bytes that don't align to any defined register; custom languages where the register set doesn't cover the patched offset; patches produced by p-code ops touching unmapped register offsets.
Related errors
- More than one state is present in
- Cannot step a negative number
- Cannot advance a negative number
- Total step count exceeds LONG_MAX
- Cannot rewind a negative number
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/166c197e3350f552.
Report an issue: GitHub.