Allow SLEIGH bitrange operator applied to dynamic varnodes

This commit is contained in:
caheckman 2022-01-03 17:03:29 -05:00
parent e440e3333f
commit 311a22c038
63 changed files with 1064 additions and 747 deletions

View file

@ -1,67 +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.pcodeCPort.slgh_compile;
import static org.junit.Assert.*;
import java.io.*;
import java.util.List;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.sleigh.grammar.Location;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
private void compare(String actual, String expectedFilename) throws IOException {
List<String> expectedList = loadTextResource(getClass(), expectedFilename);
BufferedReader actualRdr = new BufferedReader(new StringReader(actual));
for (String expectedLine : expectedList) {
String actualLine = actualRdr.readLine();
assertEquals(expectedLine, actualLine);
}
assertNull(actualRdr.readLine());
}
@Test
public void testCompilePcode() throws Exception {
SleighLanguage lang = (SleighLanguage) getSLEIGH_X86_LANGUAGE();
long uniqueBase = 0x1000000; // make sure we avoid the decompiler range
String sleighSpec =
lang.buildTranslatorTag(lang.getAddressFactory(), uniqueBase, lang.getSymbolTable());
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
"BX = CX << 2;\n" + "in1 = in2 + 7;";
PcodeParser parser = new PcodeParser(sleighSpec);
Location loc = new Location("pcodetest", 5);
parser.addOperand(loc, "in1", 0);
parser.addOperand(loc, "in2", 1);
String contructTplXml =
PcodeParser.stringifyTemplate(parser.compilePcode(pcodeStatements, "test", 200));
assertNotNull("Pcode compile failed (see log)", contructTplXml);
compare(contructTplXml, "pcode1.xml");
}
}

View file

@ -0,0 +1,252 @@
/* ###
* 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.program.model.lang;
import static org.junit.Assert.*;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.UniqueLayout;
import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.sleigh.grammar.Location;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class PcodeParserTest extends AbstractGhidraHeadlessIntegrationTest {
public boolean testVarnode(VarnodeTpl vn, String spaceName, long offset, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(spaceName)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getOffset().getReal() != offset) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testInstNextConstant(VarnodeTpl vn, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(SpaceNames.CONSTANT_SPACE_NAME)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_NEXT) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testInstNext(VarnodeTpl vn) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.J_CURSPACE) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_NEXT) {
return false;
}
if (vn.getSize().getType() != ConstTpl.J_CURSPACE_SIZE) {
return false;
}
return true;
}
public boolean testRelative(VarnodeTpl vn, int labelid, int size) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(SpaceNames.CONSTANT_SPACE_NAME)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.J_RELATIVE) {
return false;
}
if (vn.getOffset().getReal() != labelid) {
return false;
}
if (vn.getSize().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getSize().getReal() != size) {
return false;
}
return true;
}
public boolean testParameter(VarnodeTpl vn, int paramnum) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSpace().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSpace().getSelect() != ConstTpl.V_SPACE) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getOffset().getHandleIndex() != paramnum) {
return false;
}
if (vn.getOffset().getSelect() != ConstTpl.V_OFFSET) {
return false;
}
if (vn.getSize().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSize().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSize().getSelect() != ConstTpl.V_SIZE) {
return false;
}
return true;
}
public boolean testVarnodeHandleSize(VarnodeTpl vn, String spaceName, long offset,
int paramnum) {
assertNotNull(vn);
if (vn.getSpace().getType() != ConstTpl.SPACEID) {
return false;
}
if (!vn.getSpace().getSpaceId().getName().equals(spaceName)) {
return false;
}
if (vn.getOffset().getType() != ConstTpl.REAL) {
return false;
}
if (vn.getOffset().getReal() != offset) {
return false;
}
if (vn.getSize().getType() != ConstTpl.HANDLE) {
return false;
}
if (vn.getSize().getHandleIndex() != paramnum) {
return false;
}
if (vn.getSize().getSelect() != ConstTpl.V_SIZE) {
return false;
}
return true;
}
@Test
public void testCompilePcode() throws Exception {
SleighLanguage lang = (SleighLanguage) getSLEIGH_X86_LANGUAGE();
long uniqueBase = UniqueLayout.INJECT.getOffset(lang);
String pcodeStatements = "tmp:1 = inst_next;\n" + "if (AX == 0) goto inst_next;\n" +
"call [ECX];\n" + "if (BX != 1) goto <lab>;\n" + "CX = 0;\n" + "<lab>\n" +
"BX = CX << 2;\n" + "in1 = in2 + 7;";
PcodeParser parser = new PcodeParser(lang, uniqueBase);
Location loc = new Location("pcodetest", 5);
parser.addOperand(loc, "in1", 0);
parser.addOperand(loc, "in2", 1);
ConstructTpl template = parser.compilePcode(pcodeStatements, "test", 200);
assertNull(template.getResult());
assertEquals(template.getNumLabels(), 1);
OpTpl[] vec = template.getOpVec();
assertEquals(vec.length, 10);
assertEquals(vec[0].getOpcode(), PcodeOp.COPY);
assertTrue(testVarnode(vec[0].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase, 1));
assertEquals(vec[0].getInput().length, 1);
assertTrue(testInstNextConstant(vec[0].getInput()[0], 1));
assertEquals(vec[1].getOpcode(), PcodeOp.INT_EQUAL);
assertTrue(
testVarnode(vec[1].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
assertEquals(vec[1].getInput().length, 2);
assertTrue(testVarnode(vec[1].getInput()[0], "register", 0, 2));
assertTrue(testVarnode(vec[1].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
assertEquals(vec[2].getOpcode(), PcodeOp.CBRANCH);
assertNull(vec[2].getOutput());
assertEquals(vec[2].getInput().length, 2);
assertTrue(testInstNext(vec[2].getInput()[0]));
assertTrue(
testVarnode(vec[2].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x80, 1));
assertEquals(vec[3].getOpcode(), PcodeOp.CALLIND);
assertNull(vec[3].getOutput());
assertEquals(vec[3].getInput().length, 1);
assertTrue(testVarnode(vec[3].getInput()[0], "register", 4, 4));
assertEquals(vec[4].getOpcode(), PcodeOp.INT_NOTEQUAL);
assertTrue(
testVarnode(vec[4].getOutput(), SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
assertEquals(vec[4].getInput().length, 2);
assertTrue(testVarnode(vec[4].getInput()[0], "register", 0xc, 2));
assertTrue(testVarnode(vec[4].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 1, 2));
assertEquals(vec[5].getOpcode(), PcodeOp.CBRANCH);
assertNull(vec[5].getOutput());
assertEquals(vec[5].getInput().length, 2);
assertTrue(testRelative(vec[5].getInput()[0], 0, 4));
assertTrue(
testVarnode(vec[5].getInput()[1], SpaceNames.UNIQUE_SPACE_NAME, uniqueBase + 0x100, 1));
assertEquals(vec[6].getOpcode(), PcodeOp.COPY);
assertTrue(testVarnode(vec[6].getOutput(), "register", 4, 2));
assertEquals(vec[6].getInput().length, 1);
assertTrue(testVarnode(vec[6].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 2));
assertEquals(vec[7].getOpcode(), PcodeOp.PTRADD); // label
assertNull(vec[7].getOutput());
assertEquals(vec[7].getInput().length, 1);
assertTrue(testVarnode(vec[7].getInput()[0], SpaceNames.CONSTANT_SPACE_NAME, 0, 4));
assertEquals(vec[8].getOpcode(), PcodeOp.INT_LEFT);
assertTrue(testVarnode(vec[8].getOutput(), "register", 0xc, 2));
assertEquals(vec[8].getInput().length, 2);
assertTrue(testVarnode(vec[8].getInput()[0], "register", 0x4, 2));
assertTrue(testVarnode(vec[8].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 2, 4));
assertEquals(vec[9].getOpcode(), PcodeOp.INT_ADD);
assertTrue(testParameter(vec[9].getOutput(), 0));
assertEquals(vec[9].getInput().length, 2);
assertTrue(testParameter(vec[9].getInput()[0], 1));
assertTrue(
testVarnodeHandleSize(vec[9].getInput()[1], SpaceNames.CONSTANT_SPACE_NAME, 7, 0));
}
}

View file

@ -1,38 +0,0 @@
<construct_tpl labels="1">
<null/><op_tpl code="COPY"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000000"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="next"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_EQUAL"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000080"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="CBRANCH"><null/>
<varnode_tpl><const_tpl type="curspace"/><const_tpl type="next"/><const_tpl type="curspace_size"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000080"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="CALLIND"><null/>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_NOTEQUAL"><varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000100"/><const_tpl type="real" val="0x1"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0xc"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x1"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="CBRANCH"><null/>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="relative" val="0x0"/><const_tpl type="real" val="0x4"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="unique"/><const_tpl type="real" val="0x1000100"/><const_tpl type="real" val="0x1"/></varnode_tpl>
</op_tpl>
<op_tpl code="COPY"><varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x2"/></varnode_tpl>
</op_tpl>
<op_tpl code="LABEL"><null/>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x0"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_LEFT"><varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0xc"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="register"/><const_tpl type="real" val="0x4"/><const_tpl type="real" val="0x2"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x2"/><const_tpl type="real" val="0x4"/></varnode_tpl>
</op_tpl>
<op_tpl code="INT_ADD"><varnode_tpl><const_tpl type="handle" val="0" s="space"/><const_tpl type="handle" val="0" s="offset"/><const_tpl type="handle" val="0" s="size"/></varnode_tpl>
<varnode_tpl><const_tpl type="handle" val="1" s="space"/><const_tpl type="handle" val="1" s="offset"/><const_tpl type="handle" val="1" s="size"/></varnode_tpl>
<varnode_tpl><const_tpl type="spaceid" name="const"/><const_tpl type="real" val="0x7"/><const_tpl type="handle" val="0" s="size"/></varnode_tpl>
</op_tpl>
</construct_tpl>