INSERT, EXTRACT, and POPCOUNT operators on java side

This commit is contained in:
caheckman 2019-09-04 15:36:34 -04:00
parent 0fdd29b98d
commit 9c23383fa5
8 changed files with 148 additions and 460 deletions

View file

@ -15,6 +15,12 @@
*/
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.template.*;
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.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 {
private static String EOL = System.getProperty("line.separator");
@ -195,8 +194,7 @@ public class PcodeFormatter {
lineList.add(SPACE);
}
PcodeSpec opSpec = PcodeSpec.getSpec(opcode);
if (opSpec == null) {
if (opcode >= PcodeOp.PCODE_MAX) {
throw new RuntimeException("Unsupported opcode encountered: " + opcode);
}
VarnodeTpl output = op.getOutput();
@ -205,8 +203,8 @@ public class PcodeFormatter {
lineList.add(EQUALS);
}
Color color =
(opSpec.getOpCode() == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
lineList.add(new AttributedString(opSpec.getOpName(), color, metrics));
(opcode == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
lineList.add(new AttributedString(PcodeOp.getMnemonic(opcode), color, metrics));
VarnodeTpl[] inputs = op.getInput();
for (int i = 0; i < inputs.length; i++) {
if (i > 0) {

View file

@ -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);
}
}

View file

@ -15,11 +15,11 @@
*/
package ghidra.pcode.opbehavior;
import ghidra.program.model.pcode.PcodeOp;
import java.util.HashMap;
import java.util.Map;
import ghidra.program.model.pcode.PcodeOp;
public class OpBehaviorFactory {
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.CPOOLREF, new SpecialOpBehavior(PcodeOp.CPOOLREF));
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() {

View file

@ -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;
}
}

View file

@ -110,6 +110,9 @@ public enum OpCode {
CPUI_SEGMENTOP,
CPUI_CPOOLREF,
CPUI_NEW,
CPUI_INSERT,
CPUI_EXTRACT,
CPUI_POPCOUNT,
CPUI_MAX;
@ -200,16 +203,16 @@ public enum OpCode {
"UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB",
"FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL",
"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) {
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,
61, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 54, 24, 19, 27, 21, 33, 11,
29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, 2, 69, 62,
10, 59, 67, 3, 63, 56, 45 };
61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21,
33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17,
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
int min = 1; // Don't include BLANK
@ -220,12 +223,15 @@ public enum OpCode {
cur = (min + max) / 2;
ind = opcode_indices[cur]; // Get opcode in cur's sort slot
int result = opcode_name[ind].compareTo(nm);
if (result < 0)
if (result < 0) {
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
else
}
else {
return OpCode.values()[ind]; // Found the match
}
}
return null; // Name isn't an op
}

View file

@ -983,17 +983,20 @@ public abstract class PcodeCompile {
return createOpConst(location, OpCode.CPUI_INDIRECT, r.outvn.getOffset().getReal());
}
if ("cpool".equals(name)) {
if (operands.size() >= 2) { // At least two parameters
if (operands.size() >= 2) {
return createVariadic(location, OpCode.CPUI_CPOOLREF, operands);
}
}
reportError(location,name+"() expects at least two arguments");
}
if ("newobject".equals(name)) {
if (operands.size() >= 1) { // At least one parameter
if (operands.size() >= 1) {
return createVariadic(location, OpCode.CPUI_NEW, operands);
}
}
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;
}

View file

@ -88,7 +88,8 @@ public class DynamicHash {
0, // CAST is skipped
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

View file

@ -15,14 +15,14 @@
*/
package ghidra.program.model.pcode;
import java.util.*;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.UnknownInstructionException;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser;
import java.util.*;
/**
*
*
@ -36,7 +36,6 @@ import java.util.*;
* Some number of input parameter varnodes
* possible output varnode
*
* TODO: write an emulator for each PcodeOp. It should execute on a Pcode machine state.
*/
public class PcodeOp {
@ -129,8 +128,11 @@ public class PcodeOp {
public static final int SEGMENTOP = 67;
public static final int CPOOLREF = 68;
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;
@ -189,6 +191,7 @@ public class PcodeOp {
* Constructor - no output
*
* @param a address pcode is attached to
* @param sequencenumber id within a single address
* @param op operation pcode performs
* @param in inputs from pcode operation
*/
@ -200,6 +203,7 @@ public class PcodeOp {
* Constructor - no inputs, output
*
* @param a address pcode is attached to
* @param sequencenumber id within a single address
* @param op pcode operation
*/
public PcodeOp(Address a, int sequencenumber, int op) {
@ -217,8 +221,9 @@ public class PcodeOp {
* @return number of input varnodes
*/
public final int getNumInputs() {
if (input == null)
if (input == null) {
return 0;
}
return input.length;
}
@ -234,8 +239,9 @@ public class PcodeOp {
* @return the i'th input varnode
*/
public final Varnode getInput(int i) {
if (i >= input.length || i < 0)
if (i >= input.length || i < 0) {
return null;
}
return input[i];
}
@ -255,8 +261,9 @@ public class PcodeOp {
int n = input.length;
int i;
for (i = 0; i < n; ++i) {
if (input[i] == vn)
if (input[i] == vn) {
break;
}
}
return i;
}
@ -324,15 +331,18 @@ public class PcodeOp {
public final void setInput(Varnode vn, int slot) {
if (input == null) {
input = new Varnode[slot + 1];
for (int i = 0; i < input.length; ++i)
for (int i = 0; i < input.length; ++i) {
input[i] = null;
}
}
else if (slot >= input.length) {
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];
for (int i = input.length; i < newinput.length; ++i)
}
for (int i = input.length; i < newinput.length; ++i) {
newinput[i] = null;
}
input = newinput;
}
input[slot] = vn;
@ -349,10 +359,12 @@ public class PcodeOp {
return;
}
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];
for (int i = slot; i < newinput.length; ++i)
}
for (int i = slot; i < newinput.length; ++i) {
newinput[i] = input[i + 1];
}
input = newinput;
}
@ -368,10 +380,12 @@ public class PcodeOp {
return;
}
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];
for (int i = slot + 1; i < newinput.length; ++i)
}
for (int i = slot + 1; i < newinput.length; ++i) {
newinput[i] = input[i - 1];
}
newinput[slot] = vn;
input = newinput;
}
@ -409,10 +423,12 @@ public class PcodeOp {
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "code", opcode);
resBuf.append('>');
resBuf.append(seqnum.buildXML());
if (output == null)
if (output == null) {
resBuf.append("<void/>");
else
}
else {
output.buildXML(resBuf);
}
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
int spaceId = (int) input[0].getOffset();
resBuf.append("<spaceid");
@ -420,31 +436,35 @@ public class PcodeOp {
SpecXmlUtils.encodeStringAttribute(resBuf, "name", space.getName());
resBuf.append("/>");
}
else if (input.length > 0)
else if (input.length > 0) {
input[0].buildXML(resBuf);
for (int i = 1; i < input.length; ++i)
}
for (int i = 1; i < input.length; ++i) {
input[i].buildXML(resBuf);
}
resBuf.append("</op>");
}
/**
* Read pcode from SAX tree parse node.
* Read p-code from XML stream
*
* @param el SAX tree parse node
* @param pfact factory used to create pcode correctly
* @param parser is the XML stream
* @param pfact factory used to create p-code correctly
*
* @return new PcodeOp
* @throws PcodeXMLException
* @throws PcodeXMLException if XML layout is incorrect
*/
public static PcodeOp readXML(XmlPullParser parser, PcodeFactory pfact)
throws PcodeXMLException {
XmlElement el = parser.start("op");
int opc = SpecXmlUtils.decodeInt(el.getAttribute("code"));
if (!parser.peek().isStart())
if (!parser.peek().isStart()) {
throw new PcodeXMLException("Missing <seqnum> in PcodeOp");
}
SequenceNumber seqnum = SequenceNumber.readXML(parser, pfact.getAddressFactory());
if (!parser.peek().isStart())
if (!parser.peek().isStart()) {
throw new PcodeXMLException("Missing output in PcodeOp");
}
Varnode output = Varnode.readXML(parser, pfact);
ArrayList<Varnode> inputlist = new ArrayList<Varnode>();
while (parser.peek().isStart()) {
@ -468,10 +488,12 @@ public class PcodeOp {
@Override
public String toString() {
String s;
if (output != null)
if (output != null) {
s = output.toString();
else
}
else {
s = " --- ";
}
s += " " + getMnemonic() + " ";
for (int i = 0; i < input.length; i++) {
if (input[i] == null) {
@ -481,8 +503,9 @@ public class PcodeOp {
s += input[i].toString();
}
if (i < input.length - 1)
if (i < input.length - 1) {
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
*
* @return String rep of pcode operation
*
* @throws UnknownInstructionException
* @return String representation of p-code operation
*/
public final static String getMnemonic(int op) {
switch (op) {
@ -664,6 +684,12 @@ public class PcodeOp {
return "CPOOLREF";
case NEW:
return "NEW";
case INSERT:
return "INSERT";
case EXTRACT:
return "EXTRACT";
case POPCOUNT:
return "POPCOUNT";
default:
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
*
* @return the pcode op code
*
* @throws UnknownInstructionException
* @throws UnknownInstructionException if there is no matching mnemonic
*/
public static int getOpcode(String s) throws UnknownInstructionException {
if (opcodeTable == null)
if (opcodeTable == null) {
generateOpcodeTable();
}
Integer i = opcodeTable.get(s);
if (i == null)
if (i == null) {
throw new UnknownInstructionException();
}
return i.intValue();
}
}