GP-6613 Added maximumInstructionLength language property in support of inst_next2 use

This commit is contained in:
ghidra1
2026-03-27 14:29:19 -04:00
parent 9da1425d73
commit 6bfc22470a
5 changed files with 75 additions and 23 deletions

View File

@@ -70,6 +70,7 @@ public class SleighLanguage implements Language {
private int numSections = 0; // Number of named sections for this language
private int alignment = 1;
private int defaultPointerWordSize = 1; // Default wordsize to send down with pointer data-types
private OptionalInt maxInstructionLength = OptionalInt.empty();
private SleighLanguageDescription description;
private ParallelInstructionLanguageHelper parallelHelper;
private SourceFileIndexer indexer; //used to provide source file info for constructors
@@ -129,7 +130,8 @@ public class SleighLanguage implements Language {
SleighLanguageValidator.validatePspecFile(langDescription.getSpecFile());
readInitialDescription();
readInitialDescription(); // process pspec file
// should addressFactory and registers initialization be done at
// construction time?
// for now we'll assume yes.
@@ -154,6 +156,13 @@ public class SleighLanguage implements Language {
instructProtoMap = new ConcurrentHashMap<>();
initParallelHelper();
int maxLength =
getPropertyAsInt(GhidraLanguagePropertyKeys.MAXIMUM_INSTRUCTION_LENGTH, -1);
if (maxLength > 0) {
maxInstructionLength = OptionalInt.of(maxLength);
}
}
private void buildVolatileSymbolAddresses() {
@@ -1181,6 +1190,11 @@ public class SleighLanguage implements Language {
}
}
@Override
public OptionalInt getMaximumInstructionLength() {
return maxInstructionLength;
}
@Override
public String getProperty(String key) {
return properties.get(key);

View File

@@ -22,6 +22,7 @@ package ghidra.app.util;
import java.math.BigInteger;
import java.util.List;
import java.util.OptionalInt;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
@@ -113,27 +114,31 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
// NOTE: in certain cases this may not cache enough if slot size was
// specified as a minimum and not actual
int length = prototype.getLength();
int extraByteCount = prototype.getDelaySlotByteCount();
if (prototype.hasNext2Dependency()) {
/**
* NOTE: The notes about problems below apply here, too. We're assuming that the next
* instruction is at most 3 bytes longer than this instruction. Maybe that suffices, but
* be prepared to 1) Add more slack bytes, or 2) Actually parse the next instruction(s).
* The difficulty with option 2 (and why I don't just do it now) is that I need the
* initial context register value for that next instruction.
*/
extraByteCount = Math.max(length, extraByteCount);
}
if (extraByteCount == 1) {
// Assume this is a minimum size and cache enough for one
int delaySlotByteCount = prototype.getDelaySlotByteCount();
if (delaySlotByteCount == 1) {
// Assume this is a minimum delay slot size and cache enough for one
// more instruction of the same size.
length += length;
delaySlotByteCount = length;
}
else {
// NOTE: This may have a problem if delaySlotByteCount is a
// minimum byte count and more bytes are needed for delay slots.
length += extraByteCount;
length += delaySlotByteCount;
// Factor in optional inst_next2 use
int next2Length = 0;
if (prototype.hasNext2Dependency()) {
Language language = prototype.getLanguage();
OptionalInt maxNextInstructionLength = language.getMaximumInstructionLength();
if (maxNextInstructionLength.isPresent()) {
// next instruction length based upon language specified property
next2Length = maxNextInstructionLength.getAsInt();
}
else {
// next instruction length assumed to be the same as the current instruction
next2Length = length;
}
}
length += next2Length;
// Sleigh utilizes 4-byte (int) chunks when evaluating patterns
// make sure we have enough bytes to give out for any valid offset
// within the instruction

View File

@@ -15,12 +15,30 @@
*/
package ghidra.program.model.lang;
import ghidra.app.util.PseudoInstruction;
import ghidra.program.disassemble.Disassembler;
public final class GhidraLanguagePropertyKeys {
private GhidraLanguagePropertyKeys() {
}
/**
* MAXIMUM_INSTRUCTION_LENGTH specifies the maximum instruction length that a language
* may produce, including any delay slots which may be present. This value is used
* by {@link PseudoInstruction} in support of Sleigh {@code inst_next2} processing. If
* not specified a computed estimate is used by each instruction parse. If the
* Sleigh {@code inst_next2} instruction is used with variable length instructions, it
* is highly recommended that this property be specified.
*
* NOTE: It is the language (i.e., {@code slaspec/pspec}) author who needs to manually
* compute this value carefully based upon the largest possible instruction size including
* any delay slot. Ghidra will not validate this value.
*
* NOTE: This property is currently only used by Ghidra when {@code inst_next2} is used
* within the correspond {@code slaspec}.
*/
public static final String MAXIMUM_INSTRUCTION_LENGTH = "maximumInstructionLength";
/**
* CUSTOM_DISASSEMBLER_CLASS is a full class name for a language-specific
* disassembler implementation. The specified class must extend the generic

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,8 +16,7 @@
package ghidra.program.model.lang;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.*;
import ghidra.app.plugin.processors.generic.MemoryBlockDefinition;
import ghidra.program.model.address.*;
@@ -423,4 +422,15 @@ public interface Language {
*/
public AddressSetView getRegisterAddresses();
/**
* Returns an optional value which represents the maximum instruction length that a language
* may produce, including any delay slots which may be present. This value originates from
* an optional language property. This value is primarily intended when considering the
* maximum number of bytes beyond the current instruction and its delay slots which may be
* needed when determining an <I>inst_next2</I> location for a given instruction.
*
* @return maximum instruction length in bytes if specified.
*/
public OptionalInt getMaximumInstructionLength();
}

View File

@@ -767,4 +767,9 @@ class OldLanguage implements Language {
public AddressSetView getRegisterAddresses() {
return registerMgr.getRegisterAddresses();
}
@Override
public OptionalInt getMaximumInstructionLength() {
return OptionalInt.empty();
}
}