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,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();
}
}