mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-04-25 17:25:17 +02:00
GP-6613 Added maximumInstructionLength language property in support of inst_next2 use
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -767,4 +767,9 @@ class OldLanguage implements Language {
|
||||
public AddressSetView getRegisterAddresses() {
|
||||
return registerMgr.getRegisterAddresses();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getMaximumInstructionLength() {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user