diff --git a/Ghidra/Framework/Generic/src/test/java/ghidra/util/NumericUtilitiesTest.java b/Ghidra/Framework/Generic/src/test/java/ghidra/util/NumericUtilitiesTest.java index bb0bc19eac..f1eca80d11 100644 --- a/Ghidra/Framework/Generic/src/test/java/ghidra/util/NumericUtilitiesTest.java +++ b/Ghidra/Framework/Generic/src/test/java/ghidra/util/NumericUtilitiesTest.java @@ -15,8 +15,7 @@ */ package ghidra.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import java.util.*; import java.util.stream.Collectors; @@ -284,7 +283,7 @@ public class NumericUtilitiesTest { } @Test - public void testGetUnsigndeAlignedValue() { + public void testGetUnsignedAlignedValue() { assertEquals(0, NumericUtilities.getUnsignedAlignedValue(0xffffffffffffffffL, 8)); assertEquals(0xfffffffffffffff8L, diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java index 149ca9b9da..4b6a7a3cc3 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/program/emulation/PPCEmulateInstructionStateModifier.java @@ -15,6 +15,8 @@ */ package ghidra.program.emulation; +import java.math.BigInteger; + import ghidra.pcode.emulate.Emulate; import ghidra.pcode.emulate.EmulateInstructionStateModifier; import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior; @@ -22,17 +24,14 @@ import ghidra.pcode.emulate.callother.OpBehaviorOther; import ghidra.pcode.memstate.MemoryState; import ghidra.pcodeCPort.error.LowlevelError; import ghidra.program.model.pcode.Varnode; -import java.math.BigInteger; public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateModifier { - public PPCEmulateInstructionStateModifier(Emulate emu) { super(emu); - registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior()); - registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior()); - + registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior()); + registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior()); } @@ -40,7 +39,6 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM @Override public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) { - int i; if (out == null) { throw new LowlevelError("CALLOTHER: Vector permute op missing required output"); @@ -50,60 +48,64 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM throw new LowlevelError( "CALLOTHER: Vector permute op requires three non-constant varnode input"); } - for (i = 1; i < 4; i++) { + for (int i = 1; i < 4; i++) { if (inputs[i].getSize() == 0 || inputs[i].isConstant()) { throw new LowlevelError( - "CALLOTHER: Vector permute op requires three non-constant varnode input"); - + "CALLOTHER: Vector permute op requires three non-constant varnode input"); + } } Varnode in1 = inputs[1]; Varnode in2 = inputs[2]; Varnode in3 = inputs[3]; - if ((in1.getSize() != 16) || (in2.getSize() != 16) || (in3.getSize() != 16) || (out.getSize() != 16)) { + if ((in1.getSize() != 16) || (in2.getSize() != 16) || (in3.getSize() != 16) || + (out.getSize() != 16)) { throw new LowlevelError( "CALLOTHER: Vector permute op inputs/output must be 16bytes long"); } MemoryState memoryState = emu.getMemoryState(); - BigInteger src = memoryState.getBigInteger(in1,false); + // Combine two 16-byte inputs to form single 32-byte input + BigInteger src = memoryState.getBigInteger(in1, false); src = src.shiftLeft(128); src = src.or(memoryState.getBigInteger(in2, false)); - - // I need to force the srcarray and permute arrays to be a specific length - // I can find no direct way to do this which stinks. The ensureCapacity - // would work, but I need the padding at the beginning. - byte[] srcin = src.toByteArray(); - byte[] srcarray; - if (srcin.length != 32) { - i = 32-srcin.length; - srcarray = new byte[32]; - System.arraycopy(srcin, 0, srcarray, i, srcin.length); - } - else { - srcarray = srcin; - } - - byte[] pin = memoryState.getBigInteger(in3,false).toByteArray(); - byte[] permute; - if (pin.length != 16) { - i = 16 - pin.length; - permute = new byte[16]; - System.arraycopy(pin, 0, permute, i, pin.length); - } - else { - permute = pin; - } + byte[] srcin = getUnsignedValueArray(src.toByteArray(), 32); + + // Get 16-byte permute input + byte[] pin = memoryState.getBigInteger(in3, false).toByteArray(); + byte[] permute = getUnsignedValueArray(pin, 16); + + // Generate 16-byte output byte[] outarray = new byte[16]; - - for (i = 0; i < 16; i++) { - outarray[i] = srcarray[(permute[i] & 0x1f)]; + for (int i = 0; i < 16; i++) { + outarray[i] = srcin[(permute[i] & 0x1f)]; } memoryState.setValue(out, new BigInteger(outarray)); } } + /** + * Generate an unsigned value array from variable length srcBytes extending or truncating + * bytes as needed to ensure a returned length of byteLength. The MSB is located + * at byte index 0, therefore adjustments may be needed to ensure that the LSB retains + * its position in the least-significant byte. A short srcBytes array will result in + * zero-filled most-significant bytes within the result. + * @param srcBytes unsigned source value array + * @param byteLength desired result value length in bytes + * @return a value byte array of the specified byteLength + */ + private static byte[] getUnsignedValueArray(byte[] srcBytes, int byteLength) { + if (srcBytes.length == byteLength) { + return srcBytes; + } + byte[] result = new byte[byteLength]; + int srcStartIndex = Math.max(0, srcBytes.length - byteLength); // discard excessive most-significant bytes + int copyCount = Math.min(byteLength, srcBytes.length); // limit copy to requested number of bytes + int destStartIndex = byteLength - copyCount; // adjust if too few bytes provided + System.arraycopy(srcBytes, srcStartIndex, result, destStartIndex, copyCount); + return result; + } }