Add support for adc/sbb.

This commit is contained in:
Joe Hendrix 2017-10-17 11:50:23 -07:00
parent 135add62ae
commit 5eaf2605ed
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
5 changed files with 184 additions and 75 deletions

View File

@ -589,36 +589,51 @@ uext (SomeStackOffset _) _ = TopV
uext ReturnAddr _ = TopV
uext TopV _ = TopV
asBoolConst :: AbsValue w BoolType -> Maybe Bool
asBoolConst (BoolConst b) = Just b
asBoolConst TopV = Nothing
bvadc :: forall w u
. MemWidth w
=> NatRepr u
-> AbsValue w (BVType u)
-> AbsValue w (BVType u)
-> AbsValue w BoolType
-> AbsValue w (BVType u)
-- Stacks
bvadc w (StackOffset a s) (FinSet t) c
| [o0] <- Set.toList t
, BoolConst b <- c
, o <- if b then o0 + 1 else o0 =
StackOffset a $ Set.map (fromInteger . addOff w o . toInteger) s
bvadc w (FinSet t) (StackOffset a s) c
| [o0] <- Set.toList t
, BoolConst b <- c
, o <- if b then o0 + 1 else o0 =
StackOffset a $ Set.map (fromInteger . addOff w o . toInteger) s
-- Strided intervals
bvadc w v v' c
| StridedInterval si1 <- v, StridedInterval si2 <- v' = go si1 si2
| StridedInterval si <- v, IsFin s <- asFinSet "bvadc" v' = go si (SI.fromFoldable w s)
| StridedInterval si <- v', IsFin s <- asFinSet "bvadc" v = go si (SI.fromFoldable w s)
where
go :: SI.StridedInterval u -> SI.StridedInterval u -> AbsValue w (BVType u)
go si1 si2 = stridedInterval $ SI.bvadc w si1 si2 (asBoolConst c)
-- the rest
bvadc _ (StackOffset ax _) _ _ = SomeStackOffset ax
bvadc _ _ (StackOffset ax _) _ = SomeStackOffset ax
bvadc _ (SomeStackOffset ax) _ _ = SomeStackOffset ax
bvadc _ _ (SomeStackOffset ax) _ = SomeStackOffset ax
bvadc _ _ _ _ = TopV
bvadd :: forall w u
. MemWidth w
=> NatRepr u
-> AbsValue w (BVType u)
-> AbsValue w (BVType u)
-> AbsValue w (BVType u)
-- Stacks
bvadd w (StackOffset a s) (FinSet t) | [o] <- Set.toList t = do
StackOffset a $ Set.map (fromInteger . addOff w o . toInteger) s
bvadd w (FinSet t) (StackOffset a s) | [o] <- Set.toList t = do
StackOffset a $ Set.map (fromInteger . addOff w o . toInteger) s
-- Strided intervals
bvadd w v v'
| StridedInterval si1 <- v, StridedInterval si2 <- v' = go si1 si2
| StridedInterval si <- v, IsFin s <- asFinSet "bvadd" v' = go si (SI.fromFoldable w s)
| StridedInterval si <- v', IsFin s <- asFinSet "bvadd" v = go si (SI.fromFoldable w s)
where
go :: SI.StridedInterval u -> SI.StridedInterval u -> AbsValue w (BVType u)
go si1 si2 = stridedInterval $ SI.bvadd w si1 si2
-- subvalues
-- bvadd w (SubValue _n _av c) v' = bvadd w c v'
-- bvadd w v (SubValue _n _av c) = bvadd w v c
-- the rest
bvadd _ (StackOffset ax _) _ = SomeStackOffset ax
bvadd _ _ (StackOffset ax _) = SomeStackOffset ax
bvadd _ (SomeStackOffset ax) _ = SomeStackOffset ax
bvadd _ _ (SomeStackOffset ax) = SomeStackOffset ax
bvadd _ _ _ = TopV
bvadd w x y = bvadc w x y (BoolConst False)
setL :: Ord a
=> ([a] -> AbsValue w (BVType n))
@ -628,6 +643,64 @@ setL :: Ord a
setL def c l | length l > maxSetSize = def l
| otherwise = c (Set.fromList l)
-- | Subtracting
bvsbb :: forall w u
. MemWidth w
=> Memory w
-- ^ Memory used for checking code pointers.
-> NatRepr u
-> AbsValue w (BVType u)
-> AbsValue w (BVType u)
-> AbsValue w BoolType
-> AbsValue w (BVType u)
bvsbb mem w (CodePointers s b) (FinSet t) (BoolConst False)
-- If we just have zero.
| Set.null s && b = FinSet (Set.map (toUnsigned w . negate) t)
| all isJust vals && (not b || Set.singleton 0 == t) =
CodePointers (Set.fromList (catMaybes vals)) b
| otherwise = error "Losing code pointers due to bvsub."
where vals :: [Maybe (MemSegmentOff w)]
vals = do
x <- Set.toList s
y <- Set.toList t
let z = relativeSegmentAddr x & incAddr (negate y)
case asSegmentOff mem z of
Just z_mseg | segmentFlags (msegSegment z_mseg) `Perm.hasPerm` Perm.execute ->
pure (Just z_mseg)
_ ->
pure Nothing
bvsbb _ _ xv@(CodePointers xs xb) (CodePointers ys yb) (BoolConst False)
-- If we just have zero.
| Set.null ys && yb = xv
--
| all isJust vals && xb == yb =
if xb then
FinSet (Set.insert 0 (Set.fromList (catMaybes vals)))
else
FinSet (Set.fromList (catMaybes vals))
| otherwise = error "Losing code pointers due to bvsub."
where vals :: [Maybe Integer]
vals = do
x <- Set.toList xs
y <- Set.toList ys
pure (relativeSegmentAddr x `diffAddr` relativeSegmentAddr y)
bvsbb _ w (FinSet s) (asFinSet "bvsub3" -> IsFin t) (BoolConst b) =
setL (stridedInterval . SI.fromFoldable w) FinSet $ do
x <- Set.toList s
y <- Set.toList t
return $ toUnsigned w $ (x - y) - (if b then 1 else 0)
bvsbb _ w (StackOffset ax s) (asFinSet "bvsub6" -> IsFin t) (BoolConst False) =
setL (\_ -> SomeStackOffset ax) (StackOffset ax) $ do
x <- toInteger <$> Set.toList s
y <- Set.toList t
return $! fromInteger (toUnsigned w (x - y))
bvsbb _ _ (StackOffset ax _) _ _ = SomeStackOffset ax
bvsbb _ _ _ (StackOffset _ _) _ = TopV
bvsbb _ _ (SomeStackOffset ax) _ _ = SomeStackOffset ax
bvsbb _ _ _ (SomeStackOffset _) _ = TopV
bvsbb _ _ _ _ _b = TopV -- Keep the pattern checker happy
-- | Subtracting
bvsub :: forall w u
. MemWidth w
@ -643,9 +716,6 @@ bvsub mem w (CodePointers s b) (FinSet t)
| all isJust vals && (not b || Set.singleton 0 == t) =
CodePointers (Set.fromList (catMaybes vals)) b
| otherwise = error "Losing code pointers due to bvsub."
-- TODO: Fix this.
-- debug DAbsInt ("drooping " ++ show (ppIntegerSet s) ++ " " ++ show (ppIntegerSet t)) $
-- setL (stridedInterval . SI.fromFoldable w) FinSet (toInteger <$> vals)
where vals :: [Maybe (MemSegmentOff w)]
vals = do
x <- Set.toList s
@ -666,9 +736,6 @@ bvsub _ _ xv@(CodePointers xs xb) (CodePointers ys yb)
else
FinSet (Set.fromList (catMaybes vals))
| otherwise = error "Losing code pointers due to bvsub."
-- TODO: Fix this.
-- debug DAbsInt ("drooping " ++ show (ppIntegerSet s) ++ " " ++ show (ppIntegerSet t)) $
-- setL (stridedInterval . SI.fromFoldable w) FinSet (toInteger <$> vals)
where vals :: [Maybe Integer]
vals = do
x <- Set.toList xs
@ -1211,21 +1278,26 @@ finalAbsBlockState c s =
------------------------------------------------------------------------
-- Transfer functions
transferApp :: ( RegisterInfo (ArchReg a)
transferApp :: forall a ids tp
. ( RegisterInfo (ArchReg a)
, HasCallStack
)
=> AbsProcessorState (ArchReg a) ids
-> App (Value a ids) tp
-> ArchAbsValue a tp
transferApp r a =
transferApp r a = do
let t :: Value a ids utp -> ArchAbsValue a utp
t = transferValue r
case a of
Trunc v w -> trunc (transferValue r v) w
UExt v w -> uext (transferValue r v) w
BVAdd w x y -> bvadd w (transferValue r x) (transferValue r y)
BVSub w x y -> bvsub (absMem r) w (transferValue r x) (transferValue r y)
BVMul w x y -> bvmul w (transferValue r x) (transferValue r y)
BVAnd w x y -> bvand w (transferValue r x) (transferValue r y)
BVOr w x y -> bitop (.|.) w (transferValue r x) (transferValue r y)
Trunc v w -> trunc (t v) w
UExt v w -> uext (t v) w
BVAdd w x y -> bvadd w (t x) (t y)
BVAdc w x y c -> bvadc w (t x) (t y) (t c)
BVSub w x y -> bvsub (absMem r) w (t x) (t y)
BVSbb w x y b -> bvsbb (absMem r) w (t x) (t y) (t b)
BVMul w x y -> bvmul w (t x) (t y)
BVAnd w x y -> bvand w (t x) (t y)
BVOr w x y -> bitop (.|.) w (t x) (t y)
_ -> TopV
-- | Minimal information needed to parse a function call/system call
@ -1259,8 +1331,9 @@ absEvalCall params ab0 addr =
| Just Refl <- testEquality r ip_reg =
CodePointers (Set.singleton addr) False
| Just Refl <- testEquality r sp_reg =
let w = type_width (typeRepr r)
in bvadd w (ab0^.absRegState^.boundValue r) (FinSet (Set.singleton (postCallStackDelta params)))
let w = typeWidth r
in bvadd w (ab0^.absRegState^.boundValue r)
(FinSet (Set.singleton (postCallStackDelta params)))
-- Copy callee saved registers
| preserveReg params r =
ab0^.absRegState^.boundValue r

View File

@ -84,7 +84,7 @@ refineApp app av regs =
-- FIXME: HACK
-- This detects r - x < 0 || r - x == 0, i.e. r <= x
OrApp (getAssignApp -> Just (UsbbOverflows _ r xv@(BVValue sz x) (BoolValue False)))
OrApp (getAssignApp -> Just (UsbbOverflows r xv@(BVValue sz x) (BoolValue False)))
(getAssignApp -> Just (Eq (getAssignApp -> Just (BVAdd _ r' y)) (BVValue _ 0)))
| Just Refl <- testEquality r r'
, Just Refl <- testEquality y (mkLit sz (negate x))
@ -94,7 +94,7 @@ refineApp app av regs =
-- FIXME: HACK
-- This detects not (r - x < 0) && not (r - x == 0), i.e. x < r
AndApp (getAssignApp -> Just
(NotApp (getAssignApp -> Just (UsbbOverflows _ r xv@(BVValue sz x) (BoolValue False)))))
(NotApp (getAssignApp -> Just (UsbbOverflows r xv@(BVValue sz x) (BoolValue False)))))
(getAssignApp -> Just
(NotApp (getAssignApp -> Just (Eq (getAssignApp -> Just (BVAdd _ r' y)) (BVValue _ 0)))))
| Just Refl <- testEquality r r'

View File

@ -24,7 +24,7 @@ module Data.Macaw.AbsDomain.StridedInterval
-- Domain operations
, lub, lubSingleton, glb
-- Operations
, bvadd, bvmul, trunc
, bvadd, bvadc, bvmul, trunc
-- Debugging
) where
@ -336,16 +336,33 @@ bvadd sz si1 si2 =
r | m == 0 = error "bvadd given 0 stride"
| otherwise = (range si1 * (stride si1 `div` m)) + (range si2 * (stride si2 `div` m))
-- prop_bvadd :: StridedInterval (BVType 64)
-- -> StridedInterval (BVType 64)
-- -> Bool
-- prop_bvadd = mk_prop (+) bvadd
bvadc :: NatRepr u
-> StridedInterval u
-> StridedInterval u
-> Maybe Bool
-> StridedInterval u
bvadc sz si1 si2 (Just b)
| Just s <- isSingleton si1 =
clamp sz $ si2 { base = base si2 + s + (if b then 1 else 0) }
bvadc sz si1 si2 (Just b)
| Just s <- isSingleton si2 =
clamp sz $ si1 { base = base si1 + s + (if b then 1 else 0) }
bvadc sz si1 si2 b =
clamp sz $ StridedInterval { typ = typ si1
, base = base si1 + base si2 + (if b == Just True then 1 else 0)
, range = r
, stride = m }
where
m | b == Nothing = 1
| otherwise = gcd (stride si1) (stride si2)
-- We have (x + [0..a] * b) * (y + [0 .. d] * e)
-- = (x * y) + [0..a] * b * y + [0 .. d] * e * x + ([0..a] * b * [0..d] * e)
-- `subsetOf` (x * y) + [0..a] * (b * y)
-- + 0 + [0 .. d] * (e * x)
-- + 0 + ([0..a*d] * (b * e)
-- The amount to increase the range by given b.
-- We add 1 when b == Nothing due to the uncertainty
b_off | b == Nothing = 1
| otherwise = 0
r | m == 0 = error "bvadd given 0 stride"
| otherwise = (range si1 * (stride si1 `div` m)) + (range si2 * (stride si2 `div` m) + b_off)
bvmul :: NatRepr u
-> StridedInterval u

View File

@ -68,9 +68,18 @@ data App (f :: Type -> *) (tp :: Type) where
----------------------------------------------------------------------
-- Bitvector operations
-- | @BVAdd w x y@ denotes @x + y@.
BVAdd :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
-- | @BVAdc w x y c@ denotes @x + y + (c ? 1 : 0)@.
BVAdc :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> !(f BoolType) -> App f (BVType n)
-- | @BVSub w x y@ denotes @x - y@.
BVSub :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
-- | @BVSbb w x y b@ denotes @(x - y) - (b ? 1 : 0)@.
BVSbb :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> !(f BoolType) -> App f (BVType n)
-- Multiply two numbers
BVMul :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> !(f (BVType n)) -> App f (BVType n)
@ -112,32 +121,37 @@ data App (f :: Type -> *) (tp :: Type) where
--
-- This is the sum of three three values cannot be represented as an unsigned number.
UadcOverflows :: (1 <= n)
=> !(NatRepr n)
-> !(f (BVType n))
=> !(f (BVType n))
-> !(f (BVType n))
-> !(f BoolType)
-> App f BoolType
-- Add two values and a carry bit to determine if they have a signed
-- overflow.
SadcOverflows :: (1 <= n)
=> !(NatRepr n)
-> !(f (BVType n))
=> !(f (BVType n))
-> !(f (BVType n))
-> !(f BoolType)
-> App f BoolType
-- Unsigned subtract with borrow overflow
--
-- @UsbbOverflows w x y c@ should be true iff the result
-- @(toNat x - toNat y) - (c ? 1 : 0)@ is not between @0@ and @2^w-1@.
-- Since everything is unsigned, this is equivalent to @x unsignedLt (y + (c ? 1 : 0)@.
UsbbOverflows :: (1 <= n)
=> !(NatRepr n)
-> !(f (BVType n))
=> !(f (BVType n))
-> !(f (BVType n))
-> !(f BoolType)
-> App f BoolType
-- Signed subtract with borrow overflow
-- Signed subtract with borrow overflow.
--
-- @SsbbOverflows w x y c@ should be true iff the result
-- @(toInt x - toInt y) - (c ? 1 : 0)@ is not between @-2^(w-1)@ and @2^(w-1)-1@.
-- An equivalent way to express this is that x and y should have opposite signs and
-- the sign of the result should differ from the sign of x.
SsbbOverflows :: (1 <= n)
=> !(NatRepr n)
-> !(f (BVType n))
=> !(f (BVType n))
-> !(f (BVType n))
-> !(f BoolType)
-> App f BoolType
@ -159,8 +173,9 @@ data App (f :: Type -> *) (tp :: Type) where
-- | bsf "bit scan forward" returns the index of the
-- most-significant bit that is 1. An equivalent way of stating
-- this is that it returns the number "least" zero-bits. This
-- returns n if the value is zero.
-- this is that it returns the number zero-bits starting from
-- the most-significant bit location. This returns n if the
-- value is zero.
Bsr :: (1 <= n) => !(NatRepr n) -> !(f (BVType n)) -> App f (BVType n)
----------------------------------------------------------------------
@ -328,8 +343,10 @@ ppAppA pp a0 =
OrApp x y -> sexprA "or" [ pp x, pp y ]
NotApp x -> sexprA "not" [ pp x ]
XorApp x y -> sexprA "xor" [ pp x, pp y ]
BVAdd _ x y -> sexprA "bv_add" [ pp x, pp y ]
BVAdd _ x y -> sexprA "bv_add" [ pp x, pp y ]
BVAdc _ x y c -> sexprA "bv_adc" [ pp x, pp y, pp c ]
BVSub _ x y -> sexprA "bv_sub" [ pp x, pp y ]
BVSbb _ x y b -> sexprA "bv_sbb" [ pp x, pp y, pp b ]
BVMul _ x y -> sexprA "bv_mul" [ pp x, pp y ]
BVUnsignedLt x y -> sexprA "bv_ult" [ pp x, pp y ]
BVUnsignedLe x y -> sexprA "bv_ule" [ pp x, pp y ]
@ -346,10 +363,10 @@ ppAppA pp a0 =
Eq x y -> sexprA "eq" [ pp x, pp y ]
PopCount _ x -> sexprA "popcount" [ pp x ]
ReverseBytes _ x -> sexprA "reverse_bytes" [ pp x ]
UadcOverflows _ x y c -> sexprA "uadc_overflows" [ pp x, pp y, pp c ]
SadcOverflows _ x y c -> sexprA "sadc_overflows" [ pp x, pp y, pp c ]
UsbbOverflows _ x y c -> sexprA "usbb_overflows" [ pp x, pp y, pp c ]
SsbbOverflows _ x y c -> sexprA "ssbb_overflows" [ pp x, pp y, pp c ]
UadcOverflows x y c -> sexprA "uadc_overflows" [ pp x, pp y, pp c ]
SadcOverflows x y c -> sexprA "sadc_overflows" [ pp x, pp y, pp c ]
UsbbOverflows x y c -> sexprA "usbb_overflows" [ pp x, pp y, pp c ]
SsbbOverflows x y c -> sexprA "ssbb_overflows" [ pp x, pp y, pp c ]
Bsf _ x -> sexprA "bsf" [ pp x ]
Bsr _ x -> sexprA "bsr" [ pp x ]
@ -386,8 +403,10 @@ instance HasRepr (App f) TypeRepr where
NotApp{} -> knownType
XorApp{} -> knownType
BVAdd w _ _ -> BVTypeRepr w
BVSub w _ _ -> BVTypeRepr w
BVAdd w _ _ -> BVTypeRepr w
BVAdc w _ _ _ -> BVTypeRepr w
BVSub w _ _ -> BVTypeRepr w
BVSbb w _ _ _ -> BVTypeRepr w
BVMul w _ _ -> BVTypeRepr w
BVUnsignedLt{} -> knownType

View File

@ -513,22 +513,22 @@ instance S.IsValue (Expr ids) where
uadc_overflows x y c
| Just 0 <- asBVLit y, Just False <- asBoolLit c = S.false
| otherwise = app $ UadcOverflows (typeWidth x) x y c
| otherwise = app $ UadcOverflows x y c
sadc_overflows x y c
| Just 0 <- asBVLit y, Just False <- asBoolLit c = S.false
| otherwise = app $ SadcOverflows (typeWidth x) x y c
| otherwise = app $ SadcOverflows x y c
usbb_overflows x y c
| Just 0 <- asBVLit y, Just False <- asBoolLit c = S.false
-- If the borrow bit is zero, this is equivalent to unsigned x < y.
| Just False <- asBoolLit c = S.bvUlt x y
| otherwise = app $ UsbbOverflows (typeWidth x) x y c
| otherwise = app $ UsbbOverflows x y c
ssbb_overflows x y c
| Just 0 <- asBVLit y, Just False <- asBoolLit c = S.false
-- If the borrow bit is zero, this is equivalent to signed x < y.
-- FIXME: not true? | Just 0 <- asBVLit c = app $ BVSignedLt x y
| otherwise = app $ SsbbOverflows (typeWidth x) x y c
| otherwise = app $ SsbbOverflows x y c
bsf x = app $ Bsf (typeWidth x) x
bsr x = app $ Bsr (typeWidth x) x