Merge remote-tracking branch 'origin/GP-0_Dan_moveAppender'

This commit is contained in:
Ryan Kurtz 2023-04-25 06:25:07 -04:00
commit 0d0c1660f4
4 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,258 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcode;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.util.Msg;
/**
* A base implementation of {@link Appender} suitable for most cases.
*
* @param <T> the type of output of the formatter
*/
public abstract class AbstractAppender<T> implements Appender<T> {
protected final Language language;
protected final boolean indent;
/**
* Create a new appender.
*
* @param language the language of the p-code ops to format
* @param indent whether or not to indent
*/
public AbstractAppender(Language language, boolean indent) {
this.language = language;
this.indent = indent;
}
@Override
public Language getLanguage() {
return language;
}
@Override
public void appendAddressWordOffcut(long wordOffset, long offcut) {
appendString(stringifyWordOffcut(wordOffset, offcut));
}
@Override
public void appendCharacter(char c) {
if (c == '=') {
appendString(" = "); // HACK
}
else {
appendString(Character.toString(c));
}
}
@Override
public void appendIndent() {
if (indent) {
appendCharacter(' ');
appendCharacter(' ');
}
}
@Override
public void appendLabel(String label) {
appendString(label);
}
@Override
public void appendLineLabelRef(long label) {
appendString(stringifyLineLabel(label));
}
@Override
public void appendMnemonic(int opcode) {
appendString(stringifyOpMnemonic(opcode));
}
@Override
public void appendRawVarnode(AddressSpace space, long offset, long size) {
appendString(stringifyRawVarnode(space, offset, size));
}
@Override
public void appendRegister(Register register) {
appendString(stringifyRegister(register));
}
@Override
public void appendScalar(long value) {
appendString(stringifyScalarValue(value));
}
@Override
public void appendSpace(AddressSpace space) {
appendString(stringifySpace(space));
}
/**
* Append a plain string.
*
* <p>
* By default, all append method delegate to this, so either it must be implemented, or every
* other append method must be overridden to avoid ever invoking this method. The default
* implementation throws an assertion error.
*
* @param string the string to append
*/
protected void appendString(String string) {
throw new AssertionError(
"Either this shouldn't happen, or you should accept the string");
}
@Override
public void appendUnique(long offset) {
appendString(stringifyUnique(offset));
}
@Override
public void appendUserop(int id) {
appendString(stringifyUserop(language, id));
}
/**
* Covert the given line label to a string as it should be conventionally displayed.
*
* @param label the label number
* @return the display string, e.g., {@code <L1>}
*/
protected String stringifyLineLabel(long label) {
return "<" + label + ">";
}
/**
* Convert the given opcode to a string as it should be conventionally displayed.
*
* @param opcode the opcode
* @return the display string, i.e., its mnemonic
*/
protected String stringifyOpMnemonic(int opcode) {
return PcodeOp.getMnemonic(opcode);
}
/**
* Convert the given varnode to its raw conventional form.
*
* @param space the address space
* @param offset the offset in the space
* @param size the size in bytes
* @return the raw display string
*/
protected String stringifyRawVarnode(AddressSpace space, long offset, long size) {
return "(" + space.getName() + ", 0x" + Long.toHexString(offset) + ", " + size + ")";
}
/**
* Convert the given register to a string as it should be conventionally displayed.
*
* @param register the register
* @return the display string, i.e., its name
*/
protected String stringifyRegister(Register register) {
return register.getName();
}
/**
* Convert the given scalar to a string as it should be conventionally displayed.
*
* @param value the value
* @return the display string, i.e., its decimal value if small, or hex value is large
*/
protected String stringifyScalarValue(long value) {
if (value >= -64 && value <= 64) {
return Long.toString(value);
}
else {
return "0x" + Long.toHexString(value);
}
}
/**
* Convert the given address space to a string as it should be conventionally displayed.
*
* @param space the address space
* @return the display string, i.e., its name
*/
protected String stringifySpace(AddressSpace space) {
if (space == null) {
return "unknown";
}
return space.getName();
}
/**
* Convert a given unique variable to a string as it should be conventionally displayed.
*
* @param offset the variable's offset
* @return the display string, e.g., {@code $U1234}
*/
protected String stringifyUnique(long offset) {
return "$U" + Long.toHexString(offset);
}
/**
* Lookup a given userop name
*
* @param language the language containing the userop
* @param id the userop id
* @return the display string, i.e., its name, or null if it doesn't exist
*/
protected String stringifyUseropUnchecked(Language language, int id) {
if (!(language instanceof SleighLanguage)) {
throw new RuntimeException("Expected Sleigh language for CALLOTHER op");
}
return ((SleighLanguage) language).getUserDefinedOpName(id);
}
/**
* Convert a given userop to a string as it should be conventionally displayed.
*
* @param language the langauge containing the userop
* @param id the userop id
* @return the display string, i.e., its name or "unknown"
*/
protected String stringifyUserop(Language language, int id) {
String pseudoOp = stringifyUseropUnchecked(language, id);
if (pseudoOp == null) {
Msg.error(this, "Pseudo-op index not found: " + id);
pseudoOp = "unknown";
}
return pseudoOp;
}
/**
* Convert a given word-offcut style address to a string as it should be conventionally
* displayed.
*
* @param wordOffset the offset of the word in memory
* @param offcut the byte "offcut" within the word
* @return the display string, e.g., {@code 0x1234.1}
*/
protected String stringifyWordOffcut(long wordOffset, long offcut) {
String str = "0x" + Long.toHexString(wordOffset);
if (offcut != 0) {
str += "." + offcut;
}
return str;
}
}

View file

@ -0,0 +1,412 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcode;
import java.util.List;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.util.Msg;
/**
* An abstract p-code formatter which can take a list of p-code ops or op templates and consistently
* format them. The general pattern is to extend this class and specify another class which extends
* an {@link AbstractAppender}. In most cases, it is only necessary to override
* {@link #formatOpTemplate(Appender, OpTpl)}. Otherwise, most formatting logic is implemented by
* the appender.
*
* @see {@link StringPcodeFormatter} for an example
* @see {@link AbstractAppender}
* @param <T> the type of this formatter's output, e.g., {@link String}
* @param <A> the type of the appender
*/
public abstract class AbstractPcodeFormatter<T, A extends Appender<T>>
implements PcodeFormatter<T> {
/**
* A result instructing the formatter whether or not to continue
*/
protected enum FormatResult {
CONTINUE, TERMINATE;
}
/**
* Create the appender for a formatting invocation
*
* @param language the language of the p-code to format
* @param indent indicates whether each line should be indented to accommodate line labels
* @return the new appender
*/
protected abstract A createAppender(Language language, boolean indent);
/**
* Check if this formatter is configured to display raw p-code
*
* @return true if displaying raw, false otherwise
*/
protected boolean isFormatRaw() {
return false;
}
@Override
public T formatTemplates(Language language, List<OpTpl> pcodeOpTemplates) {
boolean indent = hasLabel(pcodeOpTemplates);
A appender = createAppender(language, indent);
for (OpTpl template : pcodeOpTemplates) {
if (FormatResult.TERMINATE == formatOpTemplate(appender, template)) {
break;
}
}
return appender.finish();
}
/**
* Format a single op template
*
* @param appender the appender to receive the formatted text
* @param op the template to format
* @return instructions to continue or terminate. The loop in
* {@link #formatTemplates(Language, List)} is terminated if this method returns
* {@link FormatResult#TERMINATE}.
*/
protected FormatResult formatOpTemplate(A appender, OpTpl op) {
int opcode = op.getOpcode();
if (PcodeOp.PTRADD == opcode) {
appender.appendLineLabel(op.getInput()[0].getOffset().getReal());
return FormatResult.CONTINUE;
}
appender.appendIndent();
if (opcode >= PcodeOp.PCODE_MAX) {
throw new RuntimeException("Unsupported opcode encountered: " + opcode);
}
VarnodeTpl output = op.getOutput();
if (output != null) {
formatOutput(appender, opcode, output);
appender.appendCharacter('=');
}
appender.appendMnemonic(opcode);
VarnodeTpl[] inputs = op.getInput();
for (int i = 0; i < inputs.length; i++) {
if (i > 0) {
appender.appendCharacter(',');
}
appender.appendCharacter(' ');
if (i == 0) {
if (!isFormatRaw()) {
if (opcode == PcodeOp.LOAD || opcode == PcodeOp.STORE) {
formatMemoryInput(appender, inputs[0], inputs[1]);
++i;
continue;
}
if (opcode == PcodeOp.CALLOTHER) {
formatCallOtherName(appender, inputs[0]);
continue;
}
}
if (opcode == PcodeOp.BRANCH || opcode == PcodeOp.CBRANCH) {
if (formatLabelInput(appender, inputs[i])) {
continue;
}
}
}
formatInput(appender, opcode, i, inputs[i]);
}
return FormatResult.CONTINUE;
}
/**
* Format an output varnode
*
* @param appender the appender to receive the formatted text
* @param opcode the op's opcode
* @param output the varnode to format
*/
protected void formatOutput(A appender, int opcode, VarnodeTpl output) {
formatVarnode(appender, opcode, -1, output);
}
/**
* Format an input varnode
*
* @param appender the appender to receive the formatted text
* @param opcode the op's opcode
* @param opIndex the operand's index
* @param input the varnode to format
*/
protected void formatInput(A appender, int opcode, int opIndex, VarnodeTpl input) {
formatVarnode(appender, opcode, opIndex, input);
}
/**
* Format a varnode
*
* @param appender the appender to receive the formatted text
* @param opcode the op's opcode
* @param opIndex the operand's index (-1 is output, 0 is first input)
* @param vTpl the varnode to format
*/
protected void formatVarnode(A appender, int opcode, int opIndex, VarnodeTpl vTpl) {
ConstTpl space = vTpl.getSpace();
ConstTpl offset = vTpl.getOffset();
ConstTpl size = vTpl.getSize();
if (space.getType() == ConstTpl.J_CURSPACE) {
if (offset.getType() == ConstTpl.J_START) {
appender.appendLabel("inst_start");
}
else if (offset.getType() == ConstTpl.J_NEXT) {
appender.appendLabel("inst_next");
}
else if (offset.getType() == ConstTpl.J_NEXT2) {
appender.appendLabel("inst_next2");
}
else {
formatAddress(appender, null, offset, size);
}
}
else if (space.getType() == ConstTpl.SPACEID) {
if (isFormatRaw() && offset.getType() == ConstTpl.REAL &&
size.getType() == ConstTpl.REAL) {
formatVarnodeRaw(appender, space.getSpaceId(), offset, size);
}
else {
formatVarnodeNice(appender, space.getSpaceId(), offset, size);
}
}
else {
throw new RuntimeException("Unsupported space template type: " + space.getType());
}
}
/**
* Format a varnode in nice (non-raw) form
*
* @param appender the appender to receive the formatted text
* @param space the address space of the varnode
* @param offset the offset in the address space
* @param size the size in bytes
*/
protected void formatVarnodeNice(A appender, AddressSpace space, ConstTpl offset,
ConstTpl size) {
if (space.isConstantSpace()) {
formatConstant(appender, offset, size);
}
else if (space.isUniqueSpace()) {
formatUnique(appender, offset, size);
}
else {
formatAddress(appender, space, offset, size);
}
}
/**
* Format a varnode in raw form
*
* @param appender the appender to receive the formatted text
* @param space the address space of the varnode
* @param offset the offset in the address space
* @param size the size in bytes
*/
protected void formatVarnodeRaw(A appender, AddressSpace space, ConstTpl offset,
ConstTpl size) {
appender.appendRawVarnode(space, offset.getReal(), size.getReal());
}
/**
* Format a unique variable
*
* @param appender the appender to receive the formatted text
* @param offset the offset in unique space
* @param size the size in bytes
*/
protected void formatUnique(A appender, ConstTpl offset, ConstTpl size) {
if (offset.getType() != ConstTpl.REAL) {
throw new RuntimeException("Unsupported unique offset type: " + offset.getType());
}
if (size.getType() != ConstTpl.REAL) {
throw new RuntimeException("Unsupported unique size type: " + size.getType());
}
appender.appendUnique(offset.getReal());
formatSize(appender, size);
}
/**
* Format a memory variable
*
* @param appender the appender to receive the formatted text
* @param addrSpace the address space of the variable
* @param offset the offset in the address space
* @param size the size in bytes
*/
protected void formatAddress(A appender, AddressSpace addrSpace,
ConstTpl offset, ConstTpl size) {
if (offset.getType() != ConstTpl.REAL) {
throw new RuntimeException("Unsupported address offset type: " + offset.getType());
}
long offsetValue = offset.getReal();
if (addrSpace == null) {
appender.appendCharacter('*');
appender.appendAddressWordOffcut(offsetValue, 0);
if (size.getType() != ConstTpl.J_CURSPACE_SIZE) {
formatSize(appender, size);
}
return;
}
long sizeValue = size.getReal();
Register reg =
appender.getLanguage().getRegister(addrSpace.getAddress(offsetValue), (int) sizeValue);
if (reg != null) {
appender.appendRegister(reg);
if (reg.getMinimumByteSize() > sizeValue) {
appender.appendCharacter(':');
appender.appendScalar(sizeValue);
}
return;
}
appender.appendCharacter('*');
appender.appendCharacter('[');
appender.appendSpace(addrSpace);
appender.appendCharacter(']');
long wordOffset = offsetValue / addrSpace.getAddressableUnitSize();
long offcut = offsetValue % addrSpace.getAddressableUnitSize();
appender.appendAddressWordOffcut(wordOffset, offcut);
formatSize(appender, size);
return;
}
/**
* Format a constant
*
* @param appender the appender to receive the formatted text
* @param offset the value of the constant
* @param size the size in bytes
*/
protected void formatConstant(A appender, ConstTpl offset, ConstTpl size) {
if (offset.getType() != ConstTpl.REAL) {
throw new RuntimeException("Unsupported constant offset type: " + offset.getType());
}
long value = offset.getReal();
appender.appendScalar(value);
formatSize(appender, size);
}
/**
* Format a size indicator
*
* @param appender the appender to receive the formatted text
* @param size the size in bytes
*/
protected void formatSize(A appender, ConstTpl size) {
if (size.getType() != ConstTpl.REAL) {
throw new RuntimeException("Unsupported address size type: " + size.getType());
}
if (size.getReal() != 0) {
appender.appendCharacter(':');
appender.appendScalar(size.getReal());
}
}
/**
* Format a p-code userop name (CALLOTHER)
*
* @param appender the appender to receive the formatted text
* @param input0 the constant varnode giving the userop id
*/
protected void formatCallOtherName(A appender, VarnodeTpl input0) {
if (!input0.getSpace().isConstSpace() || input0.getOffset().getType() != ConstTpl.REAL) {
throw new RuntimeException("Expected constant input[0] for CALLOTHER pcode op");
}
int id = (int) input0.getOffset().getReal();
appender.appendCharacter('"');
appender.appendUserop(id);
appender.appendCharacter('"');
}
/**
* Try to format a local label (e.g., {@code instr_next})
*
* @param appender the appender to receive the formatted text
* @param input0 the relative jump varnode
* @return true if the varnode was formatted, false if not
*/
protected boolean formatLabelInput(A appender, VarnodeTpl input0) {
if (input0.getSpace().isConstSpace() &&
input0.getOffset().getType() == ConstTpl.J_RELATIVE) {
appender.appendLineLabelRef(input0.getOffset().getReal());
return true;
}
return false;
}
/**
* Format the memory location for a LOAD or STORE op
*
* @param appender the appender to receive the formatted text
* @param input0 the const varnode giving the address space id
* @param input1 the varnode giving the address offset
*/
protected void formatMemoryInput(A appender, VarnodeTpl input0, VarnodeTpl input1) {
if (!input0.getSpace().isConstSpace() || input0.getOffset().getType() != ConstTpl.REAL) {
throw new RuntimeException("Expected constant input[0] for LOAD/STORE pcode op");
}
int id = (int) input0.getOffset().getReal();
AddressSpace space = appender.getLanguage().getAddressFactory().getAddressSpace(id);
if (space == null) {
Msg.error(this, "Address space id not found: " + id);
}
appender.appendSpace(space);
appender.appendCharacter('(');
formatVarnode(appender, -1, 0, input1);
appender.appendCharacter(')');
}
private static boolean hasLabel(List<OpTpl> pcodeOpTemplates) {
for (OpTpl op : pcodeOpTemplates) {
if (isLineLabel(op)) {
return true;
}
}
return false;
}
/**
* Check if the given template represents a line label
*
* <p>
* The {@link PcodeOp#PTRADD} op is ordinarily only use in high p-code. We reuse (read "abuse")
* it to hold a display slot for line labels later referred to in {@link PcodeOp#BRANCH} and
* {@link PcodeOp#CBRANCH} ops. This method checks if the given op template is one of those
* placeholders.
*
* @param template the op template
* @return true if it's a line label
*/
protected static boolean isLineLabel(OpTpl template) {
// Overloaded: PTRADD is high p-code
return template.getOpcode() == PcodeOp.PTRADD;
}
}

View file

@ -0,0 +1,146 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcode;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
/**
* An appender to receive formatted p-code ops.
*
* <p>
* Using {@link AbstractAppender} is highly recommended, as it makes available methods for
* displaying elements according to established Ghidra conventions.
*
* @param <T> the type of the final formatted output
*/
interface Appender<T> {
/**
* Get the language of the p-code being formatted
*
* @return
*/
Language getLanguage();
/**
* Append a line label, usually meant to be on its own line
*
* @param label the label number
*/
default void appendLineLabel(long label) {
appendLineLabelRef(label);
}
/**
* Append indentation, usually meant for the beginning of a line
*/
default void appendIndent() {
appendCharacter(' ');
appendCharacter(' ');
}
/**
* Append a reference to the given line label
*
* @param label the label number
*/
void appendLineLabelRef(long label);
/**
* Append the given opcode
*
* @param opcode the op's opcode
*/
void appendMnemonic(int opcode);
/**
* Append the the given userop
*
* @param id the userop id
*/
void appendUserop(int id);
/**
* Append the given varnode in raw form
*
* @param space the address space
* @param offset the offset in the space
* @param size the size in bytes
*/
void appendRawVarnode(AddressSpace space, long offset, long size);
/**
* Append a character
*
* <p>
* <b>NOTE:</b> if extra spacing is desired, esp., surrounding the equals sign, it must be
* appended manually.
*
* @param c the character
*/
void appendCharacter(char c);
/**
* Append an address in word-offcut form
*
* @param wordOffset the word offset
* @param offcut the byte within the word
*/
void appendAddressWordOffcut(long wordOffset, long offcut);
/**
* Append a local label
*
* @param label the label name, e.g., {@code instr_next}
*/
void appendLabel(String label);
/**
* Append a register
*
* @param register the register
*/
void appendRegister(Register register);
/**
* Append a scalar value
*
* @param value the value
*/
void appendScalar(long value);
/**
* Append an address space
*
* @param space the space
*/
void appendSpace(AddressSpace space);
/**
* Append a unique variable
*
* @param offset the offset in unique space
*/
void appendUnique(long offset);
/**
* Finish formatting and return the final result
*
* @return the final result
*/
T finish();
}

View file

@ -0,0 +1,153 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcode;
import java.util.*;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
public interface PcodeFormatter<T> {
/**
* Format the p-code ops
*
* @param language the language generating the p-code
* @param pcodeOps the p-code ops
* @return the formatted result
*/
default T formatOps(Language language, List<PcodeOp> pcodeOps) {
return formatOps(language, language.getAddressFactory(), pcodeOps);
}
/**
* Format the pcode ops with a specified {@link AddressFactory}. For use when the
* pcode ops can reference program-specific address spaces.
*
* @param language the language generating the p-code
* @param addrFactory addressFactory to use when generating pcodeop templates
* @param pcodeOps p-code ops to format
* @return the formatted result
*
*/
default T formatOps(Language language, AddressFactory addrFactory, List<PcodeOp> pcodeOps) {
return formatTemplates(language, getPcodeOpTemplates(addrFactory, pcodeOps));
}
/**
* Format the p-code op templates
*
* @param language the language generating the p-code
* @param pcodeOpTemplates the templates
* @return the formatted result
*/
T formatTemplates(Language language, List<OpTpl> pcodeOpTemplates);
/**
* Convert flattened p-code ops into templates.
*
* @param addrFactory the language's address factory
* @param pcodeOps the p-code ops to convert
* @return p-code op templates
*/
public static List<OpTpl> getPcodeOpTemplates(AddressFactory addrFactory,
List<PcodeOp> pcodeOps) {
ArrayList<OpTpl> list = new ArrayList<OpTpl>();
HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>(); // label offset to index map
for (PcodeOp pcodeOp : pcodeOps) {
int opcode = pcodeOp.getOpcode();
VarnodeTpl outputTpl = null;
Varnode v = pcodeOp.getOutput();
if (v != null) {
outputTpl = getVarnodeTpl(addrFactory, v);
}
Varnode[] inputs = pcodeOp.getInputs();
VarnodeTpl[] inputTpls = new VarnodeTpl[inputs.length];
for (int i = 0; i < inputs.length; i++) {
Varnode input = inputs[i];
if (i == 0 && (opcode == PcodeOp.BRANCH || opcode == PcodeOp.CBRANCH)) {
// Handle internal branch destination represented by constant destination
if (input.isConstant()) {
int labelOffset = pcodeOp.getSeqnum().getTime() + (int) input.getOffset();
int labelIndex;
if (labelMap.containsKey(labelOffset)) {
labelIndex = labelMap.get(labelOffset);
}
else {
labelIndex = labelMap.size();
labelMap.put(labelOffset, labelIndex);
}
ConstTpl offsetTpl = new ConstTpl(ConstTpl.J_RELATIVE, labelIndex);
ConstTpl spaceTpl = new ConstTpl(addrFactory.getConstantSpace());
ConstTpl sizeTpl = new ConstTpl(ConstTpl.REAL, 8);
inputTpls[i] = new VarnodeTpl(spaceTpl, offsetTpl, sizeTpl);
continue;
}
}
inputTpls[i] = getVarnodeTpl(addrFactory, input);
}
list.add(new OpTpl(opcode, outputTpl, inputTpls));
}
// Insert label templates from the bottom-up
ArrayList<Integer> offsetList = new ArrayList<Integer>(labelMap.keySet());
Collections.sort(offsetList);
for (int i = offsetList.size() - 1; i >= 0; i--) {
int labelOffset = offsetList.get(i);
int labelIndex = labelMap.get(labelOffset);
OpTpl labelTpl = getLabelOpTemplate(addrFactory, labelIndex);
list.add(labelOffset, labelTpl);
}
return list;
}
/**
* Create label OpTpl. Uses overloaded PcodeOp.PTRADD with input[0] = labelIndex
*
* @param addrFactory
* @param labelIndex
* @return label OpTpl
*/
private static OpTpl getLabelOpTemplate(AddressFactory addrFactory, int labelIndex) {
ConstTpl offsetTpl = new ConstTpl(ConstTpl.REAL, labelIndex);
ConstTpl spaceTpl = new ConstTpl(addrFactory.getConstantSpace());
ConstTpl sizeTpl = new ConstTpl(ConstTpl.REAL, 8);
VarnodeTpl input = new VarnodeTpl(spaceTpl, offsetTpl, sizeTpl);
return new OpTpl(PcodeOp.PTRADD, null, new VarnodeTpl[] { input });
}
private static VarnodeTpl getVarnodeTpl(AddressFactory addrFactory, Varnode v) {
ConstTpl offsetTpl = new ConstTpl(ConstTpl.REAL, v.getOffset());
AddressSpace addressSpace = addrFactory.getAddressSpace(v.getSpace());
if (addressSpace == null) {
throw new IllegalArgumentException("Unknown varnode space ID: " + v.getSpace());
}
ConstTpl spaceTpl = new ConstTpl(addressSpace);
ConstTpl sizeTpl = new ConstTpl(ConstTpl.REAL, v.getSize());
return new VarnodeTpl(spaceTpl, offsetTpl, sizeTpl);
}
}