de4dot-cex/blocks/cflow/Int64Value.cs

404 lines
12 KiB
C#
Raw Normal View History

2011-10-17 13:28:53 +08:00
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace de4dot.blocks.cflow {
class Int64Value : Value {
const ulong NO_UNKNOWN_BITS = ulong.MaxValue;
public readonly long value;
public readonly ulong validMask;
public Int64Value(long value)
: base(ValueType.Int64) {
this.value = value;
this.validMask = NO_UNKNOWN_BITS;
}
public Int64Value(long value, ulong validMask)
: base(ValueType.Int64) {
this.value = value;
this.validMask = validMask;
}
bool hasUnknownBits() {
return validMask != NO_UNKNOWN_BITS;
}
bool allBitsValid() {
return !hasUnknownBits();
}
bool isBitValid(int n) {
return isBitValid(validMask, n);
}
static bool isBitValid(ulong validMask, int n) {
return (validMask & (1UL << n)) != 0;
}
public static Int64Value createUnknown() {
return new Int64Value(0, 0UL);
}
public bool isZero() {
return hasValue(0);
}
public bool hasValue(long value) {
return allBitsValid() && this.value == value;
}
public bool hasValue(ulong value) {
return hasValue((long)value);
}
public static Int64Value Conv_U8(Int32Value a) {
//TODO: Doc says that result is sign-extended. You zero-extend it. Is that correct?
long value = (long)(ulong)(uint)a.value;
ulong validMask = a.validMask | (NO_UNKNOWN_BITS << 32);
return new Int64Value(value, validMask);
}
public static Int64Value Conv_U8(Int64Value a) {
return a;
}
public static Int64Value Conv_U8(Real8Value a) {
return new Int64Value((long)(ulong)a.value);
}
public static Int64Value Conv_I8(Int32Value a) {
long value = a.value;
ulong validMask = a.validMask;
if (isBitValid(validMask, 31))
validMask |= NO_UNKNOWN_BITS << 32;
else
validMask &= ~(NO_UNKNOWN_BITS << 32);
return new Int64Value(value, validMask);
}
public static Int64Value Conv_I8(Int64Value a) {
return a;
}
public static Int64Value Conv_I8(Real8Value a) {
return new Int64Value((long)a.value);
}
public static Int64Value Add(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return new Int64Value(a.value + b.value);
return createUnknown();
}
public static Int64Value Sub(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return new Int64Value(a.value - b.value);
return createUnknown();
}
public static Int64Value Mul(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return new Int64Value(a.value * b.value);
if (a.isZero() || b.isZero())
return new Int64Value(0);
if (a.hasValue(1))
return b;
if (b.hasValue(1))
return a;
return createUnknown();
}
public static Int64Value Div(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid()) {
try {
return new Int64Value(a.value / b.value);
}
catch (ArithmeticException) {
return createUnknown();
}
}
if (b.hasValue(1))
return a;
return createUnknown();
}
public static Int64Value Div_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid()) {
try {
return new Int64Value((int)((uint)a.value / (uint)b.value));
}
catch (ArithmeticException) {
return createUnknown();
}
}
if (b.hasValue(1))
return a;
return createUnknown();
}
public static Int64Value Rem(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid()) {
try {
return new Int64Value(a.value % b.value);
}
catch (ArithmeticException) {
return createUnknown();
}
}
if (b.hasValue(1))
return new Int64Value(0);
return createUnknown();
}
public static Int64Value Rem_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid()) {
try {
return new Int64Value((int)((uint)a.value % (uint)b.value));
}
catch (ArithmeticException) {
return createUnknown();
}
}
if (b.hasValue(1))
return new Int64Value(0);
return createUnknown();
}
public static Int64Value Neg(Int64Value a) {
if (a.allBitsValid())
return new Int64Value(-a.value);
return createUnknown();
}
public static Int64Value And(Int64Value a, Int64Value b) {
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
return new Int64Value(av & bv, (am & bm) | (((ulong)av & am) ^ am) | (((ulong)bv & bm) ^ bm));
}
public static Int64Value Or(Int64Value a, Int64Value b) {
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
return new Int64Value(av | bv, (am & bm) | ((ulong)av & am) | ((ulong)bv & bm));
}
public static Int64Value Xor(Int64Value a, Int64Value b) {
if (ReferenceEquals(a, b))
return new Int64Value(0);
long av = a.value, bv = b.value;
ulong am = a.validMask, bm = b.validMask;
return new Int64Value(av ^ bv, am & bm);
}
public static Int64Value Not(Int64Value a) {
return new Int64Value(~a.value, a.validMask);
}
public static Int64Value Shl(Int64Value a, Int32Value b) {
if (b.hasUnknownBits())
return createUnknown();
if (b.value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
return createUnknown();
int shift = b.value;
ulong validMask = (a.validMask << shift) | (ulong.MaxValue >> (sizeof(long) * 8 - shift));
return new Int64Value(a.value << shift, validMask);
}
public static Int64Value Shr(Int64Value a, Int32Value b) {
if (b.hasUnknownBits())
return createUnknown();
if (b.value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
return createUnknown();
int shift = b.value;
ulong validMask = a.validMask >> shift;
if (a.isBitValid(sizeof(long) * 8 - 1))
validMask |= (ulong.MaxValue << (sizeof(long) * 8 - shift));
return new Int64Value(a.value >> shift, validMask);
}
public static Int64Value Shr_Un(Int64Value a, Int32Value b) {
if (b.hasUnknownBits())
return createUnknown();
if (b.value == 0)
return a;
if (b.value < 0 || b.value >= sizeof(long) * 8)
return createUnknown();
int shift = b.value;
ulong validMask = (a.validMask >> shift) | (ulong.MaxValue << (sizeof(long) * 8 - shift));
return new Int64Value((long)((ulong)a.value >> shift), validMask);
}
static Int32Value create(Bool3 b) {
switch (b) {
case Bool3.False: return new Int32Value(0);
case Bool3.True: return new Int32Value(1);
default: return Int32Value.createUnknown();
}
}
public static Int32Value Ceq(Int64Value a, Int64Value b) {
return create(compareEq(a, b));
}
public static Int32Value Cgt(Int64Value a, Int64Value b) {
return create(compareGt(a, b));
}
public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
return create(compareGt_Un(a, b));
}
public static Int32Value Clt(Int64Value a, Int64Value b) {
return create(compareLt(a, b));
}
public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
return create(compareLt_Un(a, b));
}
public static Bool3 compareEq(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value == b.value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.True;
if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
return Bool3.False;
return Bool3.Unknown;
}
public static Bool3 compareNeq(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value != b.value ? Bool3.True : Bool3.False;
if (ReferenceEquals(a, b))
return Bool3.False;
if (((ulong)a.value & a.validMask & b.validMask) != ((ulong)b.value & a.validMask & b.validMask))
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 compareGt(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value > b.value ? Bool3.True : Bool3.False;
if (a.hasValue(int.MinValue))
return Bool3.False; // min > x => false
if (b.hasValue(int.MaxValue))
return Bool3.False; // x > max => false
return Bool3.Unknown;
}
public static Bool3 compareGt_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return (uint)a.value > (uint)b.value ? Bool3.True : Bool3.False;
if (a.hasValue(uint.MinValue))
return Bool3.False; // min > x => false
if (b.hasValue(uint.MaxValue))
return Bool3.False; // x > max => false
return Bool3.Unknown;
}
public static Bool3 compareGe(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value >= b.value ? Bool3.True : Bool3.False;
if (a.hasValue(int.MaxValue))
return Bool3.False; // max >= x => true
if (b.hasValue(int.MinValue))
return Bool3.False; // x >= min => true
return Bool3.Unknown;
}
public static Bool3 compareGe_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return (uint)a.value >= (uint)b.value ? Bool3.True : Bool3.False;
if (a.hasValue(uint.MaxValue))
return Bool3.False; // max >= x => true
if (b.hasValue(uint.MinValue))
return Bool3.False; // x >= min => true
return Bool3.Unknown;
}
public static Bool3 compareLe(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value <= b.value ? Bool3.True : Bool3.False;
if (a.hasValue(int.MinValue))
return Bool3.False; // min <= x => true
if (b.hasValue(int.MaxValue))
return Bool3.False; // x <= max => true
return Bool3.Unknown;
}
public static Bool3 compareLe_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return (uint)a.value <= (uint)b.value ? Bool3.True : Bool3.False;
if (a.hasValue(uint.MinValue))
return Bool3.False; // min <= x => true
if (b.hasValue(uint.MaxValue))
return Bool3.False; // x <= max => true
return Bool3.Unknown;
}
public static Bool3 compareLt(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return a.value < b.value ? Bool3.True : Bool3.False;
if (a.hasValue(int.MaxValue))
return Bool3.False; // max < x => false
if (b.hasValue(int.MinValue))
return Bool3.False; // x < min => false
return Bool3.Unknown;
}
public static Bool3 compareLt_Un(Int64Value a, Int64Value b) {
if (a.allBitsValid() && b.allBitsValid())
return (uint)a.value < (uint)b.value ? Bool3.True : Bool3.False;
if (a.hasValue(uint.MaxValue))
return Bool3.False; // max < x => false
if (b.hasValue(uint.MinValue))
return Bool3.False; // x < min => false
return Bool3.Unknown;
}
public static Bool3 compareTrue(Int64Value a) {
if (a.allBitsValid())
return a.value != 0 ? Bool3.True : Bool3.False;
if (((ulong)a.value & a.validMask) != 0)
return Bool3.True;
return Bool3.Unknown;
}
public static Bool3 compareFalse(Int64Value a) {
if (a.allBitsValid())
return a.value == 0 ? Bool3.True : Bool3.False;
if (((ulong)a.value & a.validMask) != 0)
return Bool3.False;
return Bool3.Unknown;
}
public override string ToString() {
if (allBitsValid())
return value.ToString();
return string.Format("0x{0:X8}L({1:X8})", value, validMask);
}
}
}