mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
INSERT, EXTRACT, and POPCOUNT operators on java side
This commit is contained in:
parent
0fdd29b98d
commit
9c23383fa5
8 changed files with 148 additions and 460 deletions
|
@ -15,6 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pcode;
|
package ghidra.app.util.pcode;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import docking.widgets.fieldpanel.field.AttributedString;
|
||||||
|
import docking.widgets.fieldpanel.field.CompositeAttributedString;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.app.plugin.processors.sleigh.template.*;
|
import ghidra.app.plugin.processors.sleigh.template.*;
|
||||||
import ghidra.app.util.viewer.options.OptionsGui;
|
import ghidra.app.util.viewer.options.OptionsGui;
|
||||||
|
@ -27,13 +33,6 @@ import ghidra.program.model.pcode.PcodeOp;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.FontMetrics;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.AttributedString;
|
|
||||||
import docking.widgets.fieldpanel.field.CompositeAttributedString;
|
|
||||||
|
|
||||||
public class PcodeFormatter {
|
public class PcodeFormatter {
|
||||||
|
|
||||||
private static String EOL = System.getProperty("line.separator");
|
private static String EOL = System.getProperty("line.separator");
|
||||||
|
@ -195,8 +194,7 @@ public class PcodeFormatter {
|
||||||
lineList.add(SPACE);
|
lineList.add(SPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PcodeSpec opSpec = PcodeSpec.getSpec(opcode);
|
if (opcode >= PcodeOp.PCODE_MAX) {
|
||||||
if (opSpec == null) {
|
|
||||||
throw new RuntimeException("Unsupported opcode encountered: " + opcode);
|
throw new RuntimeException("Unsupported opcode encountered: " + opcode);
|
||||||
}
|
}
|
||||||
VarnodeTpl output = op.getOutput();
|
VarnodeTpl output = op.getOutput();
|
||||||
|
@ -205,8 +203,8 @@ public class PcodeFormatter {
|
||||||
lineList.add(EQUALS);
|
lineList.add(EQUALS);
|
||||||
}
|
}
|
||||||
Color color =
|
Color color =
|
||||||
(opSpec.getOpCode() == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
|
(opcode == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
|
||||||
lineList.add(new AttributedString(opSpec.getOpName(), color, metrics));
|
lineList.add(new AttributedString(PcodeOp.getMnemonic(opcode), color, metrics));
|
||||||
VarnodeTpl[] inputs = op.getInput();
|
VarnodeTpl[] inputs = op.getInput();
|
||||||
for (int i = 0; i < inputs.length; i++) {
|
for (int i = 0; i < inputs.length; i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
|
|
|
@ -1,395 +0,0 @@
|
||||||
/* ###
|
|
||||||
* 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.template.ConstTpl;
|
|
||||||
import ghidra.app.plugin.processors.sleigh.template.VarnodeTpl;
|
|
||||||
import ghidra.program.model.address.AddressFactory;
|
|
||||||
import ghidra.program.model.address.AddressSpace;
|
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
|
||||||
import ghidra.util.exception.InvalidInputException;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
class PcodeSpec {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Input Spec Flags
|
|
||||||
//
|
|
||||||
private static final int CONSTANT = 0x01;
|
|
||||||
private static final int UNIQUE = 0x02;
|
|
||||||
private static final int ADDRESS = 0x04;
|
|
||||||
private static final int REGISTER = 0x08;
|
|
||||||
private static final int RELATIVE_ADDRESS = 0x10;
|
|
||||||
private static final int CUR_SPACE_POINTER = 0x20;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Common Input Specs
|
|
||||||
//
|
|
||||||
|
|
||||||
private static final int ANY = CONSTANT | UNIQUE | ADDRESS | REGISTER | RELATIVE_ADDRESS;
|
|
||||||
private static final int ANY_VARIABLE = UNIQUE | ADDRESS | REGISTER;
|
|
||||||
|
|
||||||
private static final int[] NO_INPUT = new int[] {};
|
|
||||||
private static final int[] ANY_ONE_INPUT = new int[] { ANY };
|
|
||||||
private static final int[] ANY_TWO_INPUTS = new int[] { ANY, ANY };
|
|
||||||
private static final int[] DIRECT_BRANCH_INPUTS = new int[] { CONSTANT | ADDRESS |
|
|
||||||
RELATIVE_ADDRESS };
|
|
||||||
private static final int[] DIRECT_CONDITIONAL_BRANCH_INPUTS = new int[] {
|
|
||||||
CONSTANT | ADDRESS | RELATIVE_ADDRESS, ANY_VARIABLE };
|
|
||||||
private static final int[] DIRECT_CALL_INPUTS = new int[] { ADDRESS };
|
|
||||||
private static final int[] INDIRECT_FLOW_INPUTS = new int[] { UNIQUE | ADDRESS | REGISTER |
|
|
||||||
RELATIVE_ADDRESS | CUR_SPACE_POINTER };
|
|
||||||
private static final int[] LOAD_INPUTS = new int[] { CONSTANT, ANY };
|
|
||||||
private static final int[] STORE_INPUTS = new int[] { CONSTANT, ANY, ANY };
|
|
||||||
private static final int[] SHIFT_INPUTS = new int[] { ANY, CONSTANT };
|
|
||||||
|
|
||||||
//
|
|
||||||
// Output Type
|
|
||||||
//
|
|
||||||
private static final int OUTPUT_NONE = 0;
|
|
||||||
private static final int OUTPUT_INPUT0_SIZE = 1;
|
|
||||||
private static final int OUTPUT_INPUT0_SIZE_EXTENDED = 2;
|
|
||||||
private static final int OUTPUT_INPUT0_SIZE_TRUNCATED = 3;
|
|
||||||
private static final int OUTPUT_INPUT1_SIZE = 4;
|
|
||||||
private static final int OUTPUT_BOOLEAN = 5;
|
|
||||||
private static final int OUTPUT_ANY_SIZE = 6;
|
|
||||||
|
|
||||||
private static HashMap<String, PcodeSpec> pcodeNameSpecMap;
|
|
||||||
private static HashMap<Integer, PcodeSpec> pcodeSpecMap;
|
|
||||||
|
|
||||||
private String opName;
|
|
||||||
private int opCode;
|
|
||||||
private int outputType;
|
|
||||||
private boolean inputSizesMustMatch;
|
|
||||||
private int[] inputSpecs;
|
|
||||||
|
|
||||||
private PcodeSpec(String opName, int opCode, int outputType, boolean inputSizesMustMatch,
|
|
||||||
int[] inputSpecs) {
|
|
||||||
this.opName = opName;
|
|
||||||
this.opCode = opCode;
|
|
||||||
this.outputType = outputType;
|
|
||||||
this.inputSizesMustMatch = inputSizesMustMatch;
|
|
||||||
this.inputSpecs = inputSpecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isAssignmentOp() {
|
|
||||||
return outputType != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean inputSizesMustMatch() {
|
|
||||||
return inputSizesMustMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getOpName() {
|
|
||||||
return opName;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getOpCode() {
|
|
||||||
return opCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getNumInputs() {
|
|
||||||
return inputSpecs.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkOutput(AddressFactory addrFactory, VarnodeTpl output, List<VarnodeTpl> inputs)
|
|
||||||
throws InvalidInputException {
|
|
||||||
|
|
||||||
if (outputType == OUTPUT_NONE) {
|
|
||||||
if (output != null) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" does not support output assignment");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (output == null) {
|
|
||||||
throw new InvalidInputException("operation " + opName + " requires output assignment");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (outputType) {
|
|
||||||
case OUTPUT_INPUT0_SIZE:
|
|
||||||
if (inputs.size() == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName + " input(s) are missing");
|
|
||||||
}
|
|
||||||
int inSize = getSize(addrFactory, inputs.get(0));
|
|
||||||
int outSize = getSize(addrFactory, output);
|
|
||||||
if (inSize != outSize) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected output size of " + inSize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUTPUT_INPUT0_SIZE_EXTENDED:
|
|
||||||
if (inputs.size() == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName + " input(s) are missing");
|
|
||||||
}
|
|
||||||
inSize = getSize(addrFactory, inputs.get(0));
|
|
||||||
outSize = getSize(addrFactory, output);
|
|
||||||
if (inSize >= outSize) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected output size larger than " + inSize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUTPUT_INPUT0_SIZE_TRUNCATED:
|
|
||||||
if (inputs.size() == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName + " input(s) are missing");
|
|
||||||
}
|
|
||||||
inSize = getSize(addrFactory, inputs.get(0));
|
|
||||||
outSize = getSize(addrFactory, output);
|
|
||||||
if (inSize <= outSize) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected output size smaller than " + inSize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUTPUT_INPUT1_SIZE:
|
|
||||||
if (inputs.size() < 2) {
|
|
||||||
throw new InvalidInputException("operation " + opName + " input(s) are missing");
|
|
||||||
}
|
|
||||||
inSize = getSize(addrFactory, inputs.get(1));
|
|
||||||
outSize = getSize(addrFactory, output);
|
|
||||||
if (inSize != outSize) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected output size of " + inSize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUTPUT_BOOLEAN:
|
|
||||||
if (getSize(addrFactory, output) != 1) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected boolean output size of 1");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OUTPUT_ANY_SIZE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("unsupported output PcodeSpec output type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSize(AddressFactory addrFactory, VarnodeTpl varnodeTpl) {
|
|
||||||
ConstTpl size = varnodeTpl.getSize();
|
|
||||||
if (size.getType() == ConstTpl.J_CURSPACE_SIZE) {
|
|
||||||
return addrFactory.getDefaultAddressSpace().getAddressableUnitSize();
|
|
||||||
}
|
|
||||||
return (int) size.getReal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate a specific varnode input template.
|
|
||||||
* @param addrFactory
|
|
||||||
* @param inputIndex
|
|
||||||
* @param input
|
|
||||||
* @param baselineSizeTpl size template for comparison when inputSizesMustMatch is true. Check not performed if null.
|
|
||||||
* @return true if input is considered valid.
|
|
||||||
*/
|
|
||||||
void checkInput(AddressFactory addrFactory, int inputIndex, VarnodeTpl input,
|
|
||||||
ConstTpl baselineSizeTpl) throws InvalidInputException {
|
|
||||||
checkInputType(addrFactory, inputIndex, input);
|
|
||||||
if (inputSizesMustMatch && baselineSizeTpl != null) {
|
|
||||||
checkInputSize(addrFactory, inputIndex, input, baselineSizeTpl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkInputSize(AddressFactory addrFactory, int inputIndex, VarnodeTpl input,
|
|
||||||
ConstTpl baselineSizeTpl) throws InvalidInputException {
|
|
||||||
int sizeType1 = baselineSizeTpl.getType();
|
|
||||||
ConstTpl sizeTpl = input.getSize();
|
|
||||||
int sizeType2 = sizeTpl.getType();
|
|
||||||
AddressSpace defaultSpace = addrFactory.getDefaultAddressSpace(); // TODO: should really correspond to the CURRENT instruction space
|
|
||||||
long size1 = sizeType1 == ConstTpl.J_CURSPACE_SIZE ? defaultSpace.getPointerSize()
|
|
||||||
: baselineSizeTpl.getReal();
|
|
||||||
long size2 = sizeType2 == ConstTpl.J_CURSPACE_SIZE ? defaultSpace.getPointerSize()
|
|
||||||
: sizeTpl.getReal();
|
|
||||||
if (size1 != size2) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" expected matching input size of " + size1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkInputType(AddressFactory addrFactory, int inputIndex, VarnodeTpl input)
|
|
||||||
throws InvalidInputException {
|
|
||||||
|
|
||||||
int mask = inputSpecs[inputIndex];
|
|
||||||
ConstTpl offset = input.getOffset();
|
|
||||||
int offsetType = offset.getType();
|
|
||||||
switch (offsetType) {
|
|
||||||
case ConstTpl.REAL:
|
|
||||||
ConstTpl space = input.getSpace();
|
|
||||||
int spaceType = space.getType();
|
|
||||||
if (spaceType == ConstTpl.SPACEID) {
|
|
||||||
AddressSpace s = space.getSpaceId();
|
|
||||||
if (space.isConstSpace()) {
|
|
||||||
if ((mask & CONSTANT) == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" - constant input not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (space.isUniqueSpace()) {
|
|
||||||
if ((mask & UNIQUE) == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" unique variable input not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // specific address or register space
|
|
||||||
|
|
||||||
if (s == null) {
|
|
||||||
throw new RuntimeException("address space not found");
|
|
||||||
}
|
|
||||||
if (s.isRegisterSpace()) {
|
|
||||||
if ((mask & REGISTER) == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" - register input not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((mask & ADDRESS) == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" - address input not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((mask & CUR_SPACE_POINTER) != 0) {
|
|
||||||
ConstTpl size = input.getSize();
|
|
||||||
int expectedSize = addrFactory.getDefaultAddressSpace().getPointerSize();
|
|
||||||
if (size.getType() == ConstTpl.REAL && size.getReal() != expectedSize) {
|
|
||||||
throw new InvalidInputException(
|
|
||||||
"incorrect indirect pointer size, expected size of " + expectedSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (spaceType == ConstTpl.J_CURSPACE) {
|
|
||||||
if ((mask & ADDRESS) == 0) {
|
|
||||||
throw new InvalidInputException("operation " + opName +
|
|
||||||
" - address input not allowed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new RuntimeException("unexpected space type (" + spaceType + ")");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConstTpl.J_START:
|
|
||||||
case ConstTpl.J_NEXT:
|
|
||||||
if ((mask & (ADDRESS | CONSTANT)) == 0) {
|
|
||||||
throw new InvalidInputException("" + opName +
|
|
||||||
" - address/constant input not allowed");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ConstTpl.J_RELATIVE:
|
|
||||||
if ((mask & RELATIVE_ADDRESS) == 0) {
|
|
||||||
throw new InvalidInputException("" + opName +
|
|
||||||
" - relative label input not allowed");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("unsupported offset type (" + offsetType + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PcodeSpec getSpec(String opName) {
|
|
||||||
initMap();
|
|
||||||
return pcodeNameSpecMap.get(opName.toUpperCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
static PcodeSpec getSpec(int opCode) {
|
|
||||||
initMap();
|
|
||||||
return pcodeSpecMap.get(opCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addSpec(String opName, int opCode, int outputType,
|
|
||||||
boolean inputSizesMustMatch, int[] inputSpecs) {
|
|
||||||
PcodeSpec opSpec = new PcodeSpec(opName, opCode, outputType, inputSizesMustMatch,
|
|
||||||
inputSpecs);
|
|
||||||
pcodeNameSpecMap.put(opName, opSpec);
|
|
||||||
pcodeSpecMap.put(opCode, opSpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initMap() {
|
|
||||||
if (pcodeNameSpecMap != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pcodeNameSpecMap = new HashMap<String, PcodeSpec>();
|
|
||||||
pcodeSpecMap = new HashMap<Integer, PcodeSpec>();
|
|
||||||
|
|
||||||
addSpec("unimpl", PcodeOp.UNIMPLEMENTED, OUTPUT_NONE, true, NO_INPUT);
|
|
||||||
|
|
||||||
addSpec("COPY", PcodeOp.COPY, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("LOAD", PcodeOp.LOAD, OUTPUT_ANY_SIZE, false, LOAD_INPUTS);
|
|
||||||
addSpec("STORE", PcodeOp.STORE, OUTPUT_NONE, false, STORE_INPUTS);
|
|
||||||
addSpec("BRANCH", PcodeOp.BRANCH, OUTPUT_NONE, false, DIRECT_BRANCH_INPUTS);
|
|
||||||
addSpec("CBRANCH", PcodeOp.CBRANCH, OUTPUT_NONE, false, DIRECT_CONDITIONAL_BRANCH_INPUTS);
|
|
||||||
addSpec("BRANCHIND", PcodeOp.BRANCHIND, OUTPUT_NONE, false, INDIRECT_FLOW_INPUTS);
|
|
||||||
addSpec("CALL", PcodeOp.CALL, OUTPUT_NONE, false, DIRECT_CALL_INPUTS);
|
|
||||||
addSpec("CALLIND", PcodeOp.CALLIND, OUTPUT_NONE, false, INDIRECT_FLOW_INPUTS);
|
|
||||||
addSpec("CALLOTHER", PcodeOp.CALLOTHER, OUTPUT_ANY_SIZE, false, null); // Special case !!
|
|
||||||
addSpec("RETURN", PcodeOp.RETURN, OUTPUT_NONE, false, INDIRECT_FLOW_INPUTS);
|
|
||||||
addSpec("INT_EQUAL", PcodeOp.INT_EQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_NOTEQUAL", PcodeOp.INT_NOTEQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SLESS", PcodeOp.INT_SLESS, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SLESSEQUAL", PcodeOp.INT_SLESSEQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_LESS", PcodeOp.INT_LESS, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_LESSEQUAL", PcodeOp.INT_LESSEQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_ZEXT", PcodeOp.INT_ZEXT, OUTPUT_INPUT0_SIZE_EXTENDED, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("INT_SEXT", PcodeOp.INT_SEXT, OUTPUT_INPUT0_SIZE_EXTENDED, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("INT_ADD", PcodeOp.INT_ADD, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SUB", PcodeOp.INT_SUB, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_CARRY", PcodeOp.INT_CARRY, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SCARRY", PcodeOp.INT_SCARRY, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SBORROW", PcodeOp.INT_SBORROW, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_2COMP", PcodeOp.INT_2COMP, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("INT_NEGATE", PcodeOp.INT_NEGATE, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("INT_XOR", PcodeOp.INT_XOR, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_AND", PcodeOp.INT_AND, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_OR", PcodeOp.INT_OR, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_LEFT", PcodeOp.INT_LEFT, OUTPUT_INPUT0_SIZE, false, SHIFT_INPUTS);
|
|
||||||
addSpec("INT_RIGHT", PcodeOp.INT_RIGHT, OUTPUT_INPUT0_SIZE, false, SHIFT_INPUTS);
|
|
||||||
addSpec("INT_SRIGHT", PcodeOp.INT_SRIGHT, OUTPUT_INPUT0_SIZE, false, SHIFT_INPUTS);
|
|
||||||
addSpec("INT_MULT", PcodeOp.INT_MULT, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_DIV", PcodeOp.INT_DIV, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SDIV", PcodeOp.INT_SDIV, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_REM", PcodeOp.INT_REM, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("INT_SREM", PcodeOp.INT_SREM, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("BOOL_NEGATE", PcodeOp.BOOL_NEGATE, OUTPUT_BOOLEAN, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("BOOL_XOR", PcodeOp.BOOL_XOR, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("BOOL_AND", PcodeOp.BOOL_AND, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("BOOL_OR", PcodeOp.BOOL_OR, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_EQUAL", PcodeOp.FLOAT_EQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_NOTEQUAL", PcodeOp.FLOAT_NOTEQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_LESS", PcodeOp.FLOAT_LESS, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_LESSEQUAL", PcodeOp.FLOAT_LESSEQUAL, OUTPUT_BOOLEAN, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_NAN", PcodeOp.FLOAT_NAN, OUTPUT_BOOLEAN, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_ADD", PcodeOp.FLOAT_ADD, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_DIV", PcodeOp.FLOAT_DIV, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_MULT", PcodeOp.FLOAT_MULT, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_SUB", PcodeOp.FLOAT_SUB, OUTPUT_INPUT0_SIZE, true, ANY_TWO_INPUTS);
|
|
||||||
addSpec("FLOAT_NEG", PcodeOp.FLOAT_NEG, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_ABS", PcodeOp.FLOAT_ABS, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_SQRT", PcodeOp.FLOAT_SQRT, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("INT2FLOAT", PcodeOp.FLOAT_INT2FLOAT, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT2FLOAT", PcodeOp.FLOAT_FLOAT2FLOAT, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT2INT", PcodeOp.FLOAT_TRUNC, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_CEIL", PcodeOp.FLOAT_CEIL, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_FLOOR", PcodeOp.FLOAT_FLOOR, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("FLOAT_ROUND", PcodeOp.FLOAT_ROUND, OUTPUT_INPUT0_SIZE, false, ANY_ONE_INPUT);
|
|
||||||
addSpec("PIECE", PcodeOp.PIECE, OUTPUT_ANY_SIZE, true, SHIFT_INPUTS); // TODO: INPUTS ??
|
|
||||||
addSpec("SUBPIECE", PcodeOp.SUBPIECE, OUTPUT_ANY_SIZE, false, SHIFT_INPUTS);
|
|
||||||
addSpec("CPOOL", PcodeOp.CPOOLREF, OUTPUT_ANY_SIZE, false, SHIFT_INPUTS);
|
|
||||||
addSpec("NEWOBJECT", PcodeOp.NEW, OUTPUT_ANY_SIZE, false, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,11 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcode.opbehavior;
|
package ghidra.pcode.opbehavior;
|
||||||
|
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
|
||||||
public class OpBehaviorFactory {
|
public class OpBehaviorFactory {
|
||||||
|
|
||||||
private static Map<Integer, OpBehavior> opBehaviorMap = new HashMap<Integer, OpBehavior>();
|
private static Map<Integer, OpBehavior> opBehaviorMap = new HashMap<Integer, OpBehavior>();
|
||||||
|
@ -101,6 +101,9 @@ public class OpBehaviorFactory {
|
||||||
opBehaviorMap.put(PcodeOp.SEGMENTOP, new SpecialOpBehavior(PcodeOp.SEGMENTOP));
|
opBehaviorMap.put(PcodeOp.SEGMENTOP, new SpecialOpBehavior(PcodeOp.SEGMENTOP));
|
||||||
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
|
opBehaviorMap.put(PcodeOp.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
|
||||||
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
|
opBehaviorMap.put(PcodeOp.NEW, new SpecialOpBehavior(PcodeOp.NEW));
|
||||||
|
opBehaviorMap.put(PcodeOp.INSERT, new SpecialOpBehavior(PcodeOp.INSERT));
|
||||||
|
opBehaviorMap.put(PcodeOp.EXTRACT, new SpecialOpBehavior(PcodeOp.EXTRACT));
|
||||||
|
opBehaviorMap.put(PcodeOp.POPCOUNT, new OpBehaviorPopcount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpBehaviorFactory() {
|
private OpBehaviorFactory() {
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* ###
|
||||||
|
* 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.pcode.opbehavior;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
|
||||||
|
public class OpBehaviorPopcount extends UnaryOpBehavior {
|
||||||
|
|
||||||
|
public OpBehaviorPopcount() {
|
||||||
|
super(PcodeOp.POPCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long evaluateUnary(int sizeout, int sizein, long val) {
|
||||||
|
val = (val & 0x5555555555555555L) + ((val >>> 1) & 0x5555555555555555L);
|
||||||
|
val = (val & 0x3333333333333333L) + ((val >>> 2) & 0x3333333333333333L);
|
||||||
|
val = (val & 0x0f0f0f0f0f0f0f0fL) + ((val >>> 4) & 0x0f0f0f0f0f0f0f0fL);
|
||||||
|
val = (val & 0x00ff00ff00ff00ffL) + ((val >>> 8) & 0x00ff00ff00ff00ffL);
|
||||||
|
val = (val & 0x0000ffff0000ffffL) + ((val >>> 16) & 0x0000ffff0000ffffL);
|
||||||
|
int res = (int) (val & 0xff);
|
||||||
|
res += (int) ((val >> 32) & 0xff);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger evaluateUnary(int sizeout, int sizein, BigInteger unsignedIn1) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -110,6 +110,9 @@ public enum OpCode {
|
||||||
CPUI_SEGMENTOP,
|
CPUI_SEGMENTOP,
|
||||||
CPUI_CPOOLREF,
|
CPUI_CPOOLREF,
|
||||||
CPUI_NEW,
|
CPUI_NEW,
|
||||||
|
CPUI_INSERT,
|
||||||
|
CPUI_EXTRACT,
|
||||||
|
CPUI_POPCOUNT,
|
||||||
|
|
||||||
CPUI_MAX;
|
CPUI_MAX;
|
||||||
|
|
||||||
|
@ -200,16 +203,16 @@ public enum OpCode {
|
||||||
"UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB",
|
"UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB",
|
||||||
"FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL",
|
"FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL",
|
||||||
"FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL",
|
"FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL",
|
||||||
"CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW" };
|
"CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT" };
|
||||||
|
|
||||||
public static String get_opname(OpCode op) {
|
public static String get_opname(OpCode op) {
|
||||||
return opcode_name[op.ordinal()];
|
return opcode_name[op.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66,
|
static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66,
|
||||||
61, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 54, 24, 19, 27, 21, 33, 11,
|
61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21,
|
||||||
29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62,
|
33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17,
|
||||||
10, 59, 67, 3, 63, 56, 45 };
|
65, 2, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 };
|
||||||
|
|
||||||
public static OpCode get_opcode(String nm) { // Use binary search to find name
|
public static OpCode get_opcode(String nm) { // Use binary search to find name
|
||||||
int min = 1; // Don't include BLANK
|
int min = 1; // Don't include BLANK
|
||||||
|
@ -220,12 +223,15 @@ public enum OpCode {
|
||||||
cur = (min + max) / 2;
|
cur = (min + max) / 2;
|
||||||
ind = opcode_indices[cur]; // Get opcode in cur's sort slot
|
ind = opcode_indices[cur]; // Get opcode in cur's sort slot
|
||||||
int result = opcode_name[ind].compareTo(nm);
|
int result = opcode_name[ind].compareTo(nm);
|
||||||
if (result < 0)
|
if (result < 0) {
|
||||||
min = cur + 1; // Everything equal or below cur is less
|
min = cur + 1; // Everything equal or below cur is less
|
||||||
else if (result > 0)
|
}
|
||||||
|
else if (result > 0) {
|
||||||
max = cur - 1; // Everything equal or above cur is greater
|
max = cur - 1; // Everything equal or above cur is greater
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return OpCode.values()[ind]; // Found the match
|
return OpCode.values()[ind]; // Found the match
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null; // Name isn't an op
|
return null; // Name isn't an op
|
||||||
}
|
}
|
||||||
|
|
|
@ -983,17 +983,20 @@ public abstract class PcodeCompile {
|
||||||
return createOpConst(location, OpCode.CPUI_INDIRECT, r.outvn.getOffset().getReal());
|
return createOpConst(location, OpCode.CPUI_INDIRECT, r.outvn.getOffset().getReal());
|
||||||
}
|
}
|
||||||
if ("cpool".equals(name)) {
|
if ("cpool".equals(name)) {
|
||||||
if (operands.size() >= 2) { // At least two parameters
|
if (operands.size() >= 2) {
|
||||||
return createVariadic(location, OpCode.CPUI_CPOOLREF, operands);
|
return createVariadic(location, OpCode.CPUI_CPOOLREF, operands);
|
||||||
}
|
}
|
||||||
reportError(location,name+"() expects at least two arguments");
|
reportError(location,name+"() expects at least two arguments");
|
||||||
}
|
}
|
||||||
if ("newobject".equals(name)) {
|
if ("newobject".equals(name)) {
|
||||||
if (operands.size() >= 1) { // At least one parameter
|
if (operands.size() >= 1) {
|
||||||
return createVariadic(location, OpCode.CPUI_NEW, operands);
|
return createVariadic(location, OpCode.CPUI_NEW, operands);
|
||||||
}
|
}
|
||||||
reportError(location,name+"() expects at least one argument");
|
reportError(location,name+"() expects at least one argument");
|
||||||
}
|
}
|
||||||
|
if ("popcount".equals(name) && hasOperands(1, operands, location, name)) {
|
||||||
|
return createOp(location, OpCode.CPUI_POPCOUNT, r);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,8 @@ public class DynamicHash {
|
||||||
|
|
||||||
0, // CAST is skipped
|
0, // CAST is skipped
|
||||||
PcodeOp.INT_ADD, PcodeOp.INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
|
PcodeOp.INT_ADD, PcodeOp.INT_ADD, // PTRADD and PTRSUB hash same as INT_ADD
|
||||||
PcodeOp.SEGMENTOP, PcodeOp.CPOOLREF, PcodeOp.NEW };
|
PcodeOp.SEGMENTOP, PcodeOp.CPOOLREF, PcodeOp.NEW, PcodeOp.INSERT, PcodeOp.EXTRACT,
|
||||||
|
PcodeOp.POPCOUNT };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An edge between a Varnode and a PcodeOp
|
* An edge between a Varnode and a PcodeOp
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.pcode;
|
package ghidra.program.model.pcode;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.UnknownInstructionException;
|
import ghidra.program.model.lang.UnknownInstructionException;
|
||||||
import ghidra.util.xml.SpecXmlUtils;
|
import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.xml.XmlElement;
|
import ghidra.xml.XmlElement;
|
||||||
import ghidra.xml.XmlPullParser;
|
import ghidra.xml.XmlPullParser;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -36,7 +36,6 @@ import java.util.*;
|
||||||
* Some number of input parameter varnodes
|
* Some number of input parameter varnodes
|
||||||
* possible output varnode
|
* possible output varnode
|
||||||
*
|
*
|
||||||
* TODO: write an emulator for each PcodeOp. It should execute on a Pcode machine state.
|
|
||||||
*/
|
*/
|
||||||
public class PcodeOp {
|
public class PcodeOp {
|
||||||
|
|
||||||
|
@ -129,8 +128,11 @@ public class PcodeOp {
|
||||||
public static final int SEGMENTOP = 67;
|
public static final int SEGMENTOP = 67;
|
||||||
public static final int CPOOLREF = 68;
|
public static final int CPOOLREF = 68;
|
||||||
public static final int NEW = 69;
|
public static final int NEW = 69;
|
||||||
|
public static final int INSERT = 70;
|
||||||
|
public static final int EXTRACT = 71;
|
||||||
|
public static final int POPCOUNT = 72;
|
||||||
|
|
||||||
public static final int PCODE_MAX = 70;
|
public static final int PCODE_MAX = 73;
|
||||||
|
|
||||||
private static Hashtable<String, Integer> opcodeTable;
|
private static Hashtable<String, Integer> opcodeTable;
|
||||||
|
|
||||||
|
@ -189,6 +191,7 @@ public class PcodeOp {
|
||||||
* Constructor - no output
|
* Constructor - no output
|
||||||
*
|
*
|
||||||
* @param a address pcode is attached to
|
* @param a address pcode is attached to
|
||||||
|
* @param sequencenumber id within a single address
|
||||||
* @param op operation pcode performs
|
* @param op operation pcode performs
|
||||||
* @param in inputs from pcode operation
|
* @param in inputs from pcode operation
|
||||||
*/
|
*/
|
||||||
|
@ -200,6 +203,7 @@ public class PcodeOp {
|
||||||
* Constructor - no inputs, output
|
* Constructor - no inputs, output
|
||||||
*
|
*
|
||||||
* @param a address pcode is attached to
|
* @param a address pcode is attached to
|
||||||
|
* @param sequencenumber id within a single address
|
||||||
* @param op pcode operation
|
* @param op pcode operation
|
||||||
*/
|
*/
|
||||||
public PcodeOp(Address a, int sequencenumber, int op) {
|
public PcodeOp(Address a, int sequencenumber, int op) {
|
||||||
|
@ -217,8 +221,9 @@ public class PcodeOp {
|
||||||
* @return number of input varnodes
|
* @return number of input varnodes
|
||||||
*/
|
*/
|
||||||
public final int getNumInputs() {
|
public final int getNumInputs() {
|
||||||
if (input == null)
|
if (input == null) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
return input.length;
|
return input.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,8 +239,9 @@ public class PcodeOp {
|
||||||
* @return the i'th input varnode
|
* @return the i'th input varnode
|
||||||
*/
|
*/
|
||||||
public final Varnode getInput(int i) {
|
public final Varnode getInput(int i) {
|
||||||
if (i >= input.length || i < 0)
|
if (i >= input.length || i < 0) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
return input[i];
|
return input[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,8 +261,9 @@ public class PcodeOp {
|
||||||
int n = input.length;
|
int n = input.length;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
if (input[i] == vn)
|
if (input[i] == vn) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -324,15 +331,18 @@ public class PcodeOp {
|
||||||
public final void setInput(Varnode vn, int slot) {
|
public final void setInput(Varnode vn, int slot) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
input = new Varnode[slot + 1];
|
input = new Varnode[slot + 1];
|
||||||
for (int i = 0; i < input.length; ++i)
|
for (int i = 0; i < input.length; ++i) {
|
||||||
input[i] = null;
|
input[i] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (slot >= input.length) {
|
else if (slot >= input.length) {
|
||||||
Varnode[] newinput = new Varnode[slot + 1];
|
Varnode[] newinput = new Varnode[slot + 1];
|
||||||
for (int i = 0; i < input.length; ++i)
|
for (int i = 0; i < input.length; ++i) {
|
||||||
newinput[i] = input[i];
|
newinput[i] = input[i];
|
||||||
for (int i = input.length; i < newinput.length; ++i)
|
}
|
||||||
|
for (int i = input.length; i < newinput.length; ++i) {
|
||||||
newinput[i] = null;
|
newinput[i] = null;
|
||||||
|
}
|
||||||
input = newinput;
|
input = newinput;
|
||||||
}
|
}
|
||||||
input[slot] = vn;
|
input[slot] = vn;
|
||||||
|
@ -349,10 +359,12 @@ public class PcodeOp {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Varnode[] newinput = new Varnode[input.length - 1];
|
Varnode[] newinput = new Varnode[input.length - 1];
|
||||||
for (int i = 0; i < slot; ++i)
|
for (int i = 0; i < slot; ++i) {
|
||||||
newinput[i] = input[i];
|
newinput[i] = input[i];
|
||||||
for (int i = slot; i < newinput.length; ++i)
|
}
|
||||||
|
for (int i = slot; i < newinput.length; ++i) {
|
||||||
newinput[i] = input[i + 1];
|
newinput[i] = input[i + 1];
|
||||||
|
}
|
||||||
input = newinput;
|
input = newinput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,10 +380,12 @@ public class PcodeOp {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Varnode[] newinput = new Varnode[input.length + 1];
|
Varnode[] newinput = new Varnode[input.length + 1];
|
||||||
for (int i = 0; i < slot; ++i)
|
for (int i = 0; i < slot; ++i) {
|
||||||
newinput[i] = input[i];
|
newinput[i] = input[i];
|
||||||
for (int i = slot + 1; i < newinput.length; ++i)
|
}
|
||||||
|
for (int i = slot + 1; i < newinput.length; ++i) {
|
||||||
newinput[i] = input[i - 1];
|
newinput[i] = input[i - 1];
|
||||||
|
}
|
||||||
newinput[slot] = vn;
|
newinput[slot] = vn;
|
||||||
input = newinput;
|
input = newinput;
|
||||||
}
|
}
|
||||||
|
@ -409,10 +423,12 @@ public class PcodeOp {
|
||||||
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "code", opcode);
|
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "code", opcode);
|
||||||
resBuf.append('>');
|
resBuf.append('>');
|
||||||
resBuf.append(seqnum.buildXML());
|
resBuf.append(seqnum.buildXML());
|
||||||
if (output == null)
|
if (output == null) {
|
||||||
resBuf.append("<void/>");
|
resBuf.append("<void/>");
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
output.buildXML(resBuf);
|
output.buildXML(resBuf);
|
||||||
|
}
|
||||||
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
|
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
|
||||||
int spaceId = (int) input[0].getOffset();
|
int spaceId = (int) input[0].getOffset();
|
||||||
resBuf.append("<spaceid");
|
resBuf.append("<spaceid");
|
||||||
|
@ -420,31 +436,35 @@ public class PcodeOp {
|
||||||
SpecXmlUtils.encodeStringAttribute(resBuf, "name", space.getName());
|
SpecXmlUtils.encodeStringAttribute(resBuf, "name", space.getName());
|
||||||
resBuf.append("/>");
|
resBuf.append("/>");
|
||||||
}
|
}
|
||||||
else if (input.length > 0)
|
else if (input.length > 0) {
|
||||||
input[0].buildXML(resBuf);
|
input[0].buildXML(resBuf);
|
||||||
for (int i = 1; i < input.length; ++i)
|
}
|
||||||
|
for (int i = 1; i < input.length; ++i) {
|
||||||
input[i].buildXML(resBuf);
|
input[i].buildXML(resBuf);
|
||||||
|
}
|
||||||
resBuf.append("</op>");
|
resBuf.append("</op>");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read pcode from SAX tree parse node.
|
* Read p-code from XML stream
|
||||||
*
|
*
|
||||||
* @param el SAX tree parse node
|
* @param parser is the XML stream
|
||||||
* @param pfact factory used to create pcode correctly
|
* @param pfact factory used to create p-code correctly
|
||||||
*
|
*
|
||||||
* @return new PcodeOp
|
* @return new PcodeOp
|
||||||
* @throws PcodeXMLException
|
* @throws PcodeXMLException if XML layout is incorrect
|
||||||
*/
|
*/
|
||||||
public static PcodeOp readXML(XmlPullParser parser, PcodeFactory pfact)
|
public static PcodeOp readXML(XmlPullParser parser, PcodeFactory pfact)
|
||||||
throws PcodeXMLException {
|
throws PcodeXMLException {
|
||||||
XmlElement el = parser.start("op");
|
XmlElement el = parser.start("op");
|
||||||
int opc = SpecXmlUtils.decodeInt(el.getAttribute("code"));
|
int opc = SpecXmlUtils.decodeInt(el.getAttribute("code"));
|
||||||
if (!parser.peek().isStart())
|
if (!parser.peek().isStart()) {
|
||||||
throw new PcodeXMLException("Missing <seqnum> in PcodeOp");
|
throw new PcodeXMLException("Missing <seqnum> in PcodeOp");
|
||||||
|
}
|
||||||
SequenceNumber seqnum = SequenceNumber.readXML(parser, pfact.getAddressFactory());
|
SequenceNumber seqnum = SequenceNumber.readXML(parser, pfact.getAddressFactory());
|
||||||
if (!parser.peek().isStart())
|
if (!parser.peek().isStart()) {
|
||||||
throw new PcodeXMLException("Missing output in PcodeOp");
|
throw new PcodeXMLException("Missing output in PcodeOp");
|
||||||
|
}
|
||||||
Varnode output = Varnode.readXML(parser, pfact);
|
Varnode output = Varnode.readXML(parser, pfact);
|
||||||
ArrayList<Varnode> inputlist = new ArrayList<Varnode>();
|
ArrayList<Varnode> inputlist = new ArrayList<Varnode>();
|
||||||
while (parser.peek().isStart()) {
|
while (parser.peek().isStart()) {
|
||||||
|
@ -468,10 +488,12 @@ public class PcodeOp {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String s;
|
String s;
|
||||||
if (output != null)
|
if (output != null) {
|
||||||
s = output.toString();
|
s = output.toString();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
s = " --- ";
|
s = " --- ";
|
||||||
|
}
|
||||||
s += " " + getMnemonic() + " ";
|
s += " " + getMnemonic() + " ";
|
||||||
for (int i = 0; i < input.length; i++) {
|
for (int i = 0; i < input.length; i++) {
|
||||||
if (input[i] == null) {
|
if (input[i] == null) {
|
||||||
|
@ -481,8 +503,9 @@ public class PcodeOp {
|
||||||
s += input[i].toString();
|
s += input[i].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < input.length - 1)
|
if (i < input.length - 1) {
|
||||||
s += " , ";
|
s += " , ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -511,13 +534,10 @@ public class PcodeOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get string representation for pcode operation
|
* Get string representation for p-code operation
|
||||||
*
|
*
|
||||||
* @param op operation code
|
* @param op operation code
|
||||||
*
|
* @return String representation of p-code operation
|
||||||
* @return String rep of pcode operation
|
|
||||||
*
|
|
||||||
* @throws UnknownInstructionException
|
|
||||||
*/
|
*/
|
||||||
public final static String getMnemonic(int op) {
|
public final static String getMnemonic(int op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -664,6 +684,12 @@ public class PcodeOp {
|
||||||
return "CPOOLREF";
|
return "CPOOLREF";
|
||||||
case NEW:
|
case NEW:
|
||||||
return "NEW";
|
return "NEW";
|
||||||
|
case INSERT:
|
||||||
|
return "INSERT";
|
||||||
|
case EXTRACT:
|
||||||
|
return "EXTRACT";
|
||||||
|
case POPCOUNT:
|
||||||
|
return "POPCOUNT";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "INVALID_OP";
|
return "INVALID_OP";
|
||||||
|
@ -671,20 +697,20 @@ public class PcodeOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the pcode op code for the given pcode mnemonic string.
|
* Get the p-code op code for the given mnemonic string.
|
||||||
|
* @param s is the mnemonic string
|
||||||
|
* @return the op code
|
||||||
*
|
*
|
||||||
* @param s pcode op mnemonic string
|
* @throws UnknownInstructionException if there is no matching mnemonic
|
||||||
*
|
|
||||||
* @return the pcode op code
|
|
||||||
*
|
|
||||||
* @throws UnknownInstructionException
|
|
||||||
*/
|
*/
|
||||||
public static int getOpcode(String s) throws UnknownInstructionException {
|
public static int getOpcode(String s) throws UnknownInstructionException {
|
||||||
if (opcodeTable == null)
|
if (opcodeTable == null) {
|
||||||
generateOpcodeTable();
|
generateOpcodeTable();
|
||||||
|
}
|
||||||
Integer i = opcodeTable.get(s);
|
Integer i = opcodeTable.get(s);
|
||||||
if (i == null)
|
if (i == null) {
|
||||||
throw new UnknownInstructionException();
|
throw new UnknownInstructionException();
|
||||||
|
}
|
||||||
return i.intValue();
|
return i.intValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue