mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
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:
parent
d9da0f0b66
commit
fccabd9950
2 changed files with 43 additions and 42 deletions
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.util;
|
package ghidra.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -284,7 +283,7 @@ public class NumericUtilitiesTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetUnsigndeAlignedValue() {
|
public void testGetUnsignedAlignedValue() {
|
||||||
|
|
||||||
assertEquals(0, NumericUtilities.getUnsignedAlignedValue(0xffffffffffffffffL, 8));
|
assertEquals(0, NumericUtilities.getUnsignedAlignedValue(0xffffffffffffffffL, 8));
|
||||||
assertEquals(0xfffffffffffffff8L,
|
assertEquals(0xfffffffffffffff8L,
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.emulation;
|
package ghidra.program.emulation;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import ghidra.pcode.emulate.Emulate;
|
import ghidra.pcode.emulate.Emulate;
|
||||||
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
|
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
|
||||||
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
|
import ghidra.pcode.emulate.callother.CountLeadingZerosOpBehavior;
|
||||||
|
@ -22,17 +24,14 @@ import ghidra.pcode.emulate.callother.OpBehaviorOther;
|
||||||
import ghidra.pcode.memstate.MemoryState;
|
import ghidra.pcode.memstate.MemoryState;
|
||||||
import ghidra.pcodeCPort.error.LowlevelError;
|
import ghidra.pcodeCPort.error.LowlevelError;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
|
public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateModifier {
|
||||||
|
|
||||||
|
|
||||||
public PPCEmulateInstructionStateModifier(Emulate emu) {
|
public PPCEmulateInstructionStateModifier(Emulate emu) {
|
||||||
super(emu);
|
super(emu);
|
||||||
|
|
||||||
registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior());
|
registerPcodeOpBehavior("countLeadingZeros", new CountLeadingZerosOpBehavior());
|
||||||
registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior());
|
registerPcodeOpBehavior("vectorPermute", new vectorPermuteOpBehavior());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +39,6 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) {
|
public void evaluate(Emulate emu, Varnode out, Varnode[] inputs) {
|
||||||
int i;
|
|
||||||
|
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
throw new LowlevelError("CALLOTHER: Vector permute op missing required output");
|
throw new LowlevelError("CALLOTHER: Vector permute op missing required output");
|
||||||
|
@ -50,60 +48,64 @@ public class PPCEmulateInstructionStateModifier extends EmulateInstructionStateM
|
||||||
throw new LowlevelError(
|
throw new LowlevelError(
|
||||||
"CALLOTHER: Vector permute op requires three non-constant varnode input");
|
"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()) {
|
if (inputs[i].getSize() == 0 || inputs[i].isConstant()) {
|
||||||
throw new LowlevelError(
|
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 in1 = inputs[1];
|
||||||
Varnode in2 = inputs[2];
|
Varnode in2 = inputs[2];
|
||||||
Varnode in3 = inputs[3];
|
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(
|
throw new LowlevelError(
|
||||||
"CALLOTHER: Vector permute op inputs/output must be 16bytes long");
|
"CALLOTHER: Vector permute op inputs/output must be 16bytes long");
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryState memoryState = emu.getMemoryState();
|
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.shiftLeft(128);
|
||||||
src = src.or(memoryState.getBigInteger(in2, false));
|
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
|
// Get 16-byte permute input
|
||||||
// would work, but I need the padding at the beginning.
|
byte[] pin = memoryState.getBigInteger(in3, false).toByteArray();
|
||||||
byte[] srcin = src.toByteArray();
|
byte[] permute = getUnsignedValueArray(pin, 16);
|
||||||
byte[] srcarray;
|
|
||||||
if (srcin.length != 32) {
|
// Generate 16-byte output
|
||||||
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[] outarray = new byte[16];
|
byte[] outarray = new byte[16];
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
for (i = 0; i < 16; i++) {
|
outarray[i] = srcin[(permute[i] & 0x1f)];
|
||||||
outarray[i] = srcarray[(permute[i] & 0x1f)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memoryState.setValue(out, new BigInteger(outarray));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue