Merge remote-tracking branch

'origin/GP-6328_Dan_fixEmulationPcEditsTruncated--SQUASHED'
(Closes #8875)
This commit is contained in:
Ryan Kurtz
2026-01-23 10:37:24 -05:00
4 changed files with 138 additions and 81 deletions
@@ -4,9 +4,9 @@
* 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.
@@ -32,6 +32,8 @@ import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
import ghidra.pcode.exec.SleighProgramCompiler.DetailedSleighException;
import ghidra.pcode.exec.SleighProgramCompiler.PcodeLogEntry;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.sleigh.grammar.Location;
import utility.function.ExceptionalCallback;
@@ -64,6 +66,21 @@ public class SleighProgramCompilerTest extends AbstractGTest {
}
}
@Test
public void testGoto64BitOffset() throws Throwable {
SleighLanguage language = SleighLanguageHelper.getMockBE64Language();
PcodeProgram program = SleighProgramCompiler.compileProgram(language, "test",
"goto 0x140000000;", PcodeUseropLibrary.NIL);
assertEquals(1, program.getCode().size());
PcodeOp branchOp = program.getCode().getFirst();
assertEquals(PcodeOp.BRANCH, branchOp.getOpcode());
assertNull(branchOp.getOutput());
assertEquals(1, branchOp.getNumInputs());
Varnode target = branchOp.getInput(0);
assertEquals(0x140000000L, target.getOffset());
}
@Test
public void testCompileProgramErrLocations() throws Throwable {
SleighLanguage language = SleighLanguageHelper.getMockBE64Language();
@@ -37,6 +37,10 @@ scope Block {
}
@members {
private static final BigInteger MAX_ULONG = new BigInteger("ffffffffffffffff", 16);
private static final BigInteger MIN_SLONG = new BigInteger("-8000000000000000", 16);
private static final BigInteger MAX_UINT = new BigInteger("ffffffff", 16);
private ParsingEnvironment env = null;
private SleighCompile sc = null;
private PcodeCompile pcode = null;
@@ -65,6 +69,37 @@ scope Block {
}
}
private long toSLong(RadixBigInteger bi) {
try {
return bi.longValueExact();
}
catch (ArithmeticException e) {
reportError(bi.location, "Integer cannot be represented as signed long: " + bi);
return bi.longValue();
}
}
private long toULong(RadixBigInteger bi) {
if (bi.compareTo(MAX_ULONG) > 0 || bi.signum() < 0) {
reportError(bi.location, "Integer cannot be represented as unsigned long: " + bi);
}
return bi.longValue();
}
private long toLong(RadixBigInteger bi) {
if (bi.compareTo(MAX_ULONG) > 0 || bi.compareTo(MIN_SLONG) < 0) {
reportError(bi.location, "Integer cannot be represented as long: " + bi);
}
return bi.longValue();
}
private int toUInt(RadixBigInteger bi) {
if (bi.compareTo(MAX_UINT) > 0 || bi.signum() < 0) {
reportError(bi.location, "Integer cannot be represented as unsigned int: " + bi);
}
return bi.intValue();
}
private void redefinedError(SleighSymbol sym, Tree t, String what) {
String msg = "symbol '" + sym.getName() + "' (from " + sym.getLocation() + ") redefined as " + what;
reportError(find(t), msg);
@@ -167,7 +202,7 @@ definition
;
aligndef
: ^(OP_ALIGNMENT i=integer) { sc.setAlignment($i.value.intValue()); }
: ^(OP_ALIGNMENT i=integer) { sc.setAlignment(toUInt($i.value)); }
;
tokendef
@@ -183,7 +218,7 @@ tokendef
if (sym != null) {
redefinedError(sym, n, "token");
} else {
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), $i.value.intValue(), 0);
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), toLong($i.value), 0);
}
}
} fielddefs)
@@ -193,7 +228,7 @@ tokendef
if (sym != null) {
redefinedError(sym, n, "token");
} else {
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), $i.value.intValue(), $s.value ==0 ? -1 : 1);
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), toLong($i.value), $s.value ==0 ? -1 : 1);
}
}
} fielddefs)
@@ -212,7 +247,7 @@ fielddef
}
: ^(t=OP_FIELDDEF n=unbound_identifier["field"] s=integer e=integer {
if (n != null) {
$fielddef::fieldQuality = new FieldQuality($n.value.getText(), find($t), $s.value.longValue(), $e.value.longValue());
$fielddef::fieldQuality = new FieldQuality($n.value.getText(), find($t), toULong($s.value), toULong($e.value));
}
} fieldmods) {
if ($fielddef.size() > 0 && $fielddef::fieldQuality != null) {
@@ -442,13 +477,13 @@ typemod
sizemod
: ^(OP_SIZE i=integer) {
$spacedef::quality.size = $i.value.intValue();
$spacedef::quality.size = toUInt($i.value);
}
;
wordsizemod
: ^(OP_WORDSIZE i=integer) {
$spacedef::quality.wordsize = $i.value.intValue();
$spacedef::quality.wordsize = toUInt($i.value);
}
;
@@ -462,7 +497,7 @@ varnodedef
throw new SleighError("Unsupported size: " + String.format("0x\%x", size),
l.second.get(0));
}
sc.defineVarnodes(s, $offset.value.longValue(), $size.value.intValue(), l.first, l.second);
sc.defineVarnodes(s, toULong($offset.value), toUInt($size.value), l.first, l.second);
}
;
@@ -497,7 +532,7 @@ bitrangedef
sbitrange
: ^(OP_BITRANGE ^(OP_IDENTIFIER s=.) b=varnode_symbol["bitrange definition", true] i=integer j=integer) {
sc.defineBitrange(find(s), $s.getText(), b, $i.value.intValue(), $j.value.intValue());
sc.defineBitrange(find(s), $s.getText(), b, toUInt($i.value), toUInt($j.value));
}
;
@@ -516,10 +551,10 @@ intblist returns [VectorSTL<Long> value]
@init {
$value = new VectorSTL<Long>();
}
: ^(OP_INTBLIST (n=intbpart { $value.push_back(n.longValue()); } )*)
: ^(OP_INTBLIST (n=intbpart { $value.push_back(toLong(n)); } )*)
;
intbpart returns [BigInteger value]
intbpart returns [RadixBigInteger value]
: t=OP_WILDCARD { $value = new RadixBigInteger(find(t), "BADBEEF", 16); }
| ^(OP_NEGATE i=integer) { $value = i.negate(); }
| i=integer { $value = i; }
@@ -805,7 +840,7 @@ pexpression returns [PatternExpression value]
// | ^(OP_APPLY n=identifier o=pexpression2_operands) { $value = $n.value + "(" + $o.value + ")"; } // for globalset!!!
| y=pattern_symbol["pattern expression"] { $value = $y.expr; }
| i=integer { $value = new ConstantValue(i.location, i.longValue()); }
| i=integer { $value = new ConstantValue(i.location, toLong(i)); }
| ^(OP_PARENTHESIZED l=pexpression) { $value = l; }
;
@@ -825,7 +860,7 @@ pexpression2 returns [PatternExpression value]
// | ^(OP_APPLY n=identifier o=pexpression2_operands) { $value = $n.value + "(" + $o.value + ")"; } // for globalset!!!
| y=pattern_symbol2["pattern expression"] { $value = $y.expr; }
| i=integer { $value = new ConstantValue(i.location, i.longValue()); }
| i=integer { $value = new ConstantValue(i.location, toLong(i)); }
| ^(OP_PARENTHESIZED l=pexpression2) { $value = l; }
;
@@ -1095,7 +1130,7 @@ statement
declaration
: ^(OP_LOCAL n=unbound_identifier["sized local declaration"] i=integer) {
pcode.newLocalDefinition(find(n), n.getText(), $i.value.intValue());
pcode.newLocalDefinition(find(n), n.getText(), toUInt($i.value));
}
| ^(OP_LOCAL n=unbound_identifier["local declaration"]) {
pcode.newLocalDefinition(find(n), n.getText());
@@ -1162,13 +1197,13 @@ assignment returns [VectorSTL<OpTpl> value]
$code_block::stmtLocation = find(t);
}
: ^(t=OP_ASSIGN ^(OP_BITRANGE ss=specific_symbol["bit range assignment"] a=integer b=integer) e=expr) {
$value = pcode.assignBitRange(find(t), ss.getVarnode(), $a.value.intValue(), $b.value.intValue(), e);
$value = pcode.assignBitRange(find(t), ss.getVarnode(), toUInt($a.value), toUInt($b.value), e);
}
| ^(t=OP_ASSIGN ^(OP_DECLARATIVE_SIZE n=unbound_identifier["variable declaration/assignment"] i=integer) e=expr) {
$value = pcode.newOutput(find(n), true, e, n.getText(), $i.value.intValue());
$value = pcode.newOutput(find(n), true, e, n.getText(), toUInt($i.value));
}
| ^(OP_LOCAL t=OP_ASSIGN ^(OP_DECLARATIVE_SIZE n=unbound_identifier["variable declaration/assignment"] i=integer) e=expr) {
$value = pcode.newOutput(find(n), true, e, n.getText(), $i.value.intValue());
$value = pcode.newOutput(find(n), true, e, n.getText(), toUInt($i.value));
}
| ^(OP_LOCAL t=OP_ASSIGN n=unbound_identifier["variable declaration/assignment"] e=expr) {
$value = pcode.newOutput(find(n), true, e, n.getText());
@@ -1207,7 +1242,7 @@ assignment returns [VectorSTL<OpTpl> value]
;
bitrange returns [ExprTree value]
: ^(t=OP_BITRANGE ss=specific_symbol["bit range"] a=integer b=integer) { $value = pcode.createBitRange(find(t), ss, $a.value.intValue(), $b.value.intValue()); }
: ^(t=OP_BITRANGE ss=specific_symbol["bit range"] a=integer b=integer) { $value = pcode.createBitRange(find(t), ss, toUInt($a.value), toUInt($b.value)); }
;
sizedstar returns [Pair<StarQuality, ExprTree> value]
@@ -1219,7 +1254,7 @@ sizedstar returns [Pair<StarQuality, ExprTree> value]
}
: ^(t=OP_DEREFERENCE s=space_symbol["sized star operator"] i=integer e=expr) {
q = new StarQuality(find(t));
q.setSize($i.value.intValue());
q.setSize(toUInt($i.value));
q.setId(new ConstTpl(s.getSpace()));
}
| ^(t=OP_DEREFERENCE s=space_symbol["sized star operator"] e=expr) {
@@ -1229,7 +1264,7 @@ sizedstar returns [Pair<StarQuality, ExprTree> value]
}
| ^(t=OP_DEREFERENCE i=integer e=expr) {
q = new StarQuality(find(t));
q.setSize($i.value.intValue());
q.setSize(toUInt($i.value));
q.setId(new ConstTpl(pcode.getDefaultSpace()));
}
| ^(t=OP_DEREFERENCE e=expr) {
@@ -1248,7 +1283,7 @@ sizedstarv returns [Pair<StarQuality, VarnodeTpl> value]
}
: ^(t=OP_DEREFERENCE s=space_symbol["sized star operator"] i=integer ss=specific_symbol["varnode reference"]) {
q = new StarQuality(find(t));
q.setSize($i.value.intValue());
q.setSize(toUInt($i.value));
q.setId(new ConstTpl(s.getSpace()));
}
| ^(t=OP_DEREFERENCE s=space_symbol["sized star operator"] ss=specific_symbol["varnode reference"]) {
@@ -1258,7 +1293,7 @@ sizedstarv returns [Pair<StarQuality, VarnodeTpl> value]
}
| ^(t=OP_DEREFERENCE i=integer ss=specific_symbol["varnode reference"]) {
q = new StarQuality(find(t));
q.setSize($i.value.intValue());
q.setSize(toUInt($i.value));
q.setId(new ConstTpl(pcode.getDefaultSpace()));
}
| ^(t=OP_DEREFERENCE ss=specific_symbol["varnode reference"]) {
@@ -1358,13 +1393,13 @@ jumpdest[String purpose] returns [ExprTree value]
}
| ^(t=OP_JUMPDEST_ABSOLUTE i=integer) {
value = new ExprTree(find(t), new VarnodeTpl(find(t), new ConstTpl(ConstTpl.const_type.j_curspace),
new ConstTpl(ConstTpl.const_type.real, $i.value.intValue()),
new ConstTpl(ConstTpl.const_type.real, toULong($i.value)),
new ConstTpl(ConstTpl.const_type.j_curspace_size)));
}
| ^(t=OP_JUMPDEST_RELATIVE i=integer s=space_symbol[purpose]) {
AddrSpace spc = s.getSpace();
value = new ExprTree(find(t), new VarnodeTpl(find(t), new ConstTpl(spc),
new ConstTpl(ConstTpl.const_type.real, $i.value.intValue()),
new ConstTpl(ConstTpl.const_type.real, toSLong($i.value)),
new ConstTpl(ConstTpl.const_type.real, spc.getAddrSize())));
}
| ^(t=OP_JUMPDEST_LABEL l=label) {
@@ -1471,13 +1506,13 @@ expr returns [ExprTree value]
| v=varnode_or_bitsym["expression"] { $value = $v.value; }
| b=bitrange { $value = $b.value; }
| i=integer { $value = new ExprTree(i.location, new VarnodeTpl(i.location, new ConstTpl(pcode.getConstantSpace()),
new ConstTpl(ConstTpl.const_type.real, $i.value.longValue()),
new ConstTpl(ConstTpl.const_type.real, toLong($i.value)),
new ConstTpl(ConstTpl.const_type.real, 0)));
}
| ^(OP_PARENTHESIZED l=expr) { $value = l; }
| ^(t=OP_BITRANGE2 ss=specific_symbol["expression"] i=integer) {
$value = pcode.createBitRange(find(t), ss, 0, ($i.value.intValue() * 8));
$value = pcode.createBitRange(find(t), ss, 0, toUInt($i.value) * 8);
}
;
@@ -1563,15 +1598,15 @@ expr_operands returns [VectorSTL<ExprTree> value]
varnode_adorned returns [VarnodeTpl value]
: ^(t=OP_TRUNCATION_SIZE n=integer m=integer) {
if ($m.value.longValue() > 8) {
if (toULong($m.value) > 8) {
reportError(find(t), "Constant varnode size must not exceed 8 (" +
$n.value.longValue() + ":" + $m.value.longValue() + ")");
$n.value + ":" + $m.value + ")");
}
$value = new VarnodeTpl(find(t), new ConstTpl(pcode.getConstantSpace()),
new ConstTpl(ConstTpl.const_type.real, $n.value.longValue()),
new ConstTpl(ConstTpl.const_type.real, $m.value.longValue()));
new ConstTpl(ConstTpl.const_type.real, toLong($n.value)),
new ConstTpl(ConstTpl.const_type.real, toULong($m.value)));
}
| ^(OP_ADDRESS_OF ^(OP_SIZING_SIZE i=integer) v=varnode) { $value = pcode.addressOf(v, $i.value.intValue()); }
| ^(OP_ADDRESS_OF ^(OP_SIZING_SIZE i=integer) v=varnode) { $value = pcode.addressOf(v, toUInt($i.value)); }
| ^(OP_ADDRESS_OF v=varnode) { $value = pcode.addressOf(v, 0); }
;
@@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.
@@ -20,55 +19,61 @@ import java.math.BigInteger;
import java.util.Random;
public class RadixBigInteger extends BigInteger {
private static final long serialVersionUID = -7927157989937732244L;
protected int preferredRadix = 10;
public final Location location;
private static final long serialVersionUID = -7927157989937732244L;
protected int preferredRadix = 10;
public final Location location;
public RadixBigInteger(Location location, byte[] val) {
super(val);
this.location = location;
}
public RadixBigInteger(Location location, byte[] val) {
super(val);
this.location = location;
}
public RadixBigInteger(Location location, String val) {
super(val);
this.location = location;
}
public RadixBigInteger(Location location, String val) {
super(val);
this.location = location;
}
public RadixBigInteger(Location location, int signum, byte[] magnitude) {
super(signum, magnitude);
this.location = location;
}
public RadixBigInteger(Location location, int signum, byte[] magnitude) {
super(signum, magnitude);
this.location = location;
}
public RadixBigInteger(Location location, String val, int radix) {
super(val, radix);
preferredRadix = radix;
this.location = location;
}
public RadixBigInteger(Location location, String val, int radix) {
super(val, radix);
preferredRadix = radix;
this.location = location;
}
public RadixBigInteger(Location location, int numBits, Random rnd) {
super(numBits, rnd);
this.location = location;
}
public RadixBigInteger(Location location, int numBits, Random rnd) {
super(numBits, rnd);
this.location = location;
}
public RadixBigInteger(Location location, int bitLength, int certainty, Random rnd) {
super(bitLength, certainty, rnd);
this.location = location;
}
public RadixBigInteger(Location location, int bitLength, int certainty, Random rnd) {
super(bitLength, certainty, rnd);
this.location = location;
}
public int getPreferredRadix() {
return preferredRadix;
}
public int getPreferredRadix() {
return preferredRadix;
}
public void setPreferredRadix(int preferredRadix) {
this.preferredRadix = preferredRadix;
}
public void setPreferredRadix(int preferredRadix) {
this.preferredRadix = preferredRadix;
}
@Override
public String toString() {
String s = super.toString(preferredRadix);
if (preferredRadix == 16) {
s = "0x" + s;
}
return s;
}
@Override
public String toString() {
String s = super.toString(preferredRadix);
if (preferredRadix == 16) {
s = "0x" + s;
}
return s;
}
@Override
public RadixBigInteger negate() {
BigInteger n = super.negate();
return new RadixBigInteger(location, n.toByteArray());
}
}
@@ -5,9 +5,9 @@
* 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.
@@ -118,7 +118,7 @@ public class SleighCompileRegressionTest extends AbstractGenericTest {
String command = getCppSleighCompilerForArch();
ProcessBuilder processBuilder =
new ProcessBuilder(command, "-DMIPS=../../../../../../ghidra/Ghidra/Processors/MIPS",
"-D8051=../../../../../../ghidra/Ghidra/Processors/8051",
"-D8051=../../../../../../ghidra/Ghidra/Processors/8051", "-y",
inputFile.getAbsolutePath(), targetFile.getAbsolutePath());
processBuilder.directory(inputFile.getParentFile().getFile(false));
Process process = processBuilder.start();
@@ -168,7 +168,7 @@ public class SleighCompileRegressionTest extends AbstractGenericTest {
private int runActualCompiler(File inputFile, File actualFile)
throws JDOMException, IOException, RecognitionException {
return SleighCompileLauncher.runMain(new String[] { "-DBaseDir=../../../../../../",
"-DMIPS=ghidra/Ghidra/Processors/MIPS", "-D8051=ghidra/Ghidra/Processors/8051",
"-DMIPS=ghidra/Ghidra/Processors/MIPS", "-D8051=ghidra/Ghidra/Processors/8051", "-y",
inputFile.getAbsolutePath(), actualFile.getAbsolutePath() });
}