diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java index 149bbecfe5..51de5d2fdb 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/pcode/exec/SleighProgramCompilerTest.java @@ -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(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g index 39effb8a3d..b28cdb24e0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g +++ b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g @@ -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 value] @init { $value = new VectorSTL(); } - : ^(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 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 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 value] @@ -1219,7 +1254,7 @@ sizedstar returns [Pair 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 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 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 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 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); } ; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/RadixBigInteger.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/RadixBigInteger.java index 532a0c2d13..7ad4baaba2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/RadixBigInteger.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/RadixBigInteger.java @@ -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()); + } } diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/pcodeCPort/slgh_compile/regression/SleighCompileRegressionTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/pcodeCPort/slgh_compile/regression/SleighCompileRegressionTest.java index 3b854a2620..ede28167bd 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/pcodeCPort/slgh_compile/regression/SleighCompileRegressionTest.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/pcodeCPort/slgh_compile/regression/SleighCompileRegressionTest.java @@ -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() }); }