mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +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,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() {
|
||||
|
|
|
@ -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_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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue