GT-3148: Corrected conversion of BigInteger to byte array to remove

array out of bounds exception in PowerPC vectorPermute pcodeop
This commit is contained in:
ghidorahrex 2019-09-12 12:08:46 -04:00 committed by ghidra1
parent d9da0f0b66
commit fccabd9950
2 changed files with 43 additions and 42 deletions

View file

@ -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,

View file

@ -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,25 +24,21 @@ 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());
}
private class vectorPermuteOpBehavior implements OpBehaviorOther {
@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,7 +48,7 @@ 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");
@ -61,49 +59,53 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM
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));
byte[] srcin = getUnsignedValueArray(src.toByteArray(), 32);
// 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;
}
// Get 16-byte permute input
byte[] pin = memoryState.getBigInteger(in3, false).toByteArray();
byte[] permute = getUnsignedValueArray(pin, 16);
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;
}
// 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;
}
}