mirror of
https://github.com/GaloisInc/macaw.git
synced 2024-11-24 08:53:12 +03:00
Add JumpTable bounds; remove code discovery dependency on syscall.
This commit is contained in:
parent
3014a23a70
commit
e962608f2c
@ -43,6 +43,7 @@ library
|
|||||||
Data.Macaw.DebugLogging
|
Data.Macaw.DebugLogging
|
||||||
Data.Macaw.Discovery
|
Data.Macaw.Discovery
|
||||||
Data.Macaw.Discovery.Info
|
Data.Macaw.Discovery.Info
|
||||||
|
Data.Macaw.Discovery.JumpBounds
|
||||||
Data.Macaw.Dwarf
|
Data.Macaw.Dwarf
|
||||||
Data.Macaw.Memory
|
Data.Macaw.Memory
|
||||||
Data.Macaw.Memory.ElfLoader
|
Data.Macaw.Memory.ElfLoader
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
module Data.Macaw.AbsDomain.AbsState
|
module Data.Macaw.AbsDomain.AbsState
|
||||||
( AbsBlockState
|
( AbsBlockState
|
||||||
, setAbsIP
|
, setAbsIP
|
||||||
, mkAbsBlockState
|
|
||||||
, absRegState
|
, absRegState
|
||||||
, absStackHasReturnAddr
|
, absStackHasReturnAddr
|
||||||
|
, CallParams(..)
|
||||||
|
, postCallAbsState
|
||||||
, AbsBlockStack
|
, AbsBlockStack
|
||||||
, StackEntry(..)
|
, StackEntry(..)
|
||||||
, ArchAbsValue
|
, ArchAbsValue
|
||||||
@ -62,6 +63,7 @@ import Control.Lens
|
|||||||
import Control.Monad.State.Strict
|
import Control.Monad.State.Strict
|
||||||
import Data.Bits
|
import Data.Bits
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
|
import Data.Functor
|
||||||
import Data.Int
|
import Data.Int
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
@ -78,6 +80,7 @@ import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
|
|||||||
import qualified Data.Macaw.AbsDomain.StridedInterval as SI
|
import qualified Data.Macaw.AbsDomain.StridedInterval as SI
|
||||||
import Data.Macaw.CFG
|
import Data.Macaw.CFG
|
||||||
import Data.Macaw.DebugLogging
|
import Data.Macaw.DebugLogging
|
||||||
|
import Data.Macaw.Discovery.JumpBounds
|
||||||
import Data.Macaw.Memory
|
import Data.Macaw.Memory
|
||||||
import qualified Data.Macaw.Memory.Permissions as Perm
|
import qualified Data.Macaw.Memory.Permissions as Perm
|
||||||
import Data.Macaw.Types
|
import Data.Macaw.Types
|
||||||
@ -91,6 +94,10 @@ addOff w o v = toUnsigned w (o + v)
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- AbsDomain
|
-- AbsDomain
|
||||||
|
|
||||||
|
-- | This represents an lattice order.
|
||||||
|
--
|
||||||
|
-- Elements are comparable for equality, have a partial order, a top element,
|
||||||
|
-- and the ability to join to elements.
|
||||||
class Eq d => AbsDomain d where
|
class Eq d => AbsDomain d where
|
||||||
-- | The top element
|
-- | The top element
|
||||||
top :: d
|
top :: d
|
||||||
@ -317,15 +324,6 @@ isEmpty (CodePointers s b) = Set.null s && not b
|
|||||||
isEmpty (FinSet s) = Set.null s
|
isEmpty (FinSet s) = Set.null s
|
||||||
isEmpty _ = False
|
isEmpty _ = False
|
||||||
|
|
||||||
-- -----------------------------------------------------------------------------
|
|
||||||
-- Instances
|
|
||||||
|
|
||||||
{-
|
|
||||||
-- | Returns true if set just contains 0.
|
|
||||||
isZeroPtr :: Set Word64 -> Bool
|
|
||||||
isZeroPtr s = Set.size s == 1 && Set.findMin s == 0
|
|
||||||
-}
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Joining abstract values
|
-- Joining abstract values
|
||||||
|
|
||||||
@ -907,6 +905,7 @@ ppAbsStack m = vcat (pp <$> Map.toDescList m)
|
|||||||
data AbsBlockState r
|
data AbsBlockState r
|
||||||
= AbsBlockState { _absRegState :: !(RegState r (AbsValue (RegAddrWidth r)))
|
= AbsBlockState { _absRegState :: !(RegState r (AbsValue (RegAddrWidth r)))
|
||||||
, _startAbsStack :: !(AbsBlockStack (RegAddrWidth r))
|
, _startAbsStack :: !(AbsBlockStack (RegAddrWidth r))
|
||||||
|
, _initIndexBounds :: !(InitialIndexBounds r)
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving instance MapF.OrdF r => Eq (AbsBlockState r)
|
deriving instance MapF.OrdF r => Eq (AbsBlockState r)
|
||||||
@ -919,10 +918,8 @@ absRegState = lens _absRegState (\s v -> s { _absRegState = v })
|
|||||||
startAbsStack :: Simple Lens (AbsBlockState r) (AbsBlockStack (RegAddrWidth r))
|
startAbsStack :: Simple Lens (AbsBlockState r) (AbsBlockStack (RegAddrWidth r))
|
||||||
startAbsStack = lens _startAbsStack (\s v -> s { _startAbsStack = v })
|
startAbsStack = lens _startAbsStack (\s v -> s { _startAbsStack = v })
|
||||||
|
|
||||||
traceUnless :: Bool -> String -> a -> a
|
initIndexBounds :: Simple Lens (AbsBlockState r) (InitialIndexBounds r)
|
||||||
traceUnless True _ = id
|
initIndexBounds = lens _initIndexBounds (\s v -> s { _initIndexBounds = v })
|
||||||
traceUnless False msg = debug DAbsInt msg
|
|
||||||
|
|
||||||
|
|
||||||
instance ( RegisterInfo r
|
instance ( RegisterInfo r
|
||||||
)
|
)
|
||||||
@ -930,6 +927,7 @@ instance ( RegisterInfo r
|
|||||||
|
|
||||||
top = AbsBlockState { _absRegState = mkRegState (\_ -> TopV)
|
top = AbsBlockState { _absRegState = mkRegState (\_ -> TopV)
|
||||||
, _startAbsStack = Map.empty
|
, _startAbsStack = Map.empty
|
||||||
|
, _initIndexBounds = arbitraryInitialBounds
|
||||||
}
|
}
|
||||||
|
|
||||||
joinD x y | regs_changed = Just $! z
|
joinD x y | regs_changed = Just $! z
|
||||||
@ -940,7 +938,7 @@ instance ( RegisterInfo r
|
|||||||
x_stk = x^.startAbsStack
|
x_stk = x^.startAbsStack
|
||||||
y_stk = y^.startAbsStack
|
y_stk = y^.startAbsStack
|
||||||
|
|
||||||
(zs,(regs_changed,dropped)) = flip runState (False, Set.empty) $ do
|
(z,(regs_changed,_dropped)) = flip runState (False, Set.empty) $ do
|
||||||
z_regs <- mkRegStateM $ \r -> do
|
z_regs <- mkRegStateM $ \r -> do
|
||||||
let xr = xs^.boundValue r
|
let xr = xs^.boundValue r
|
||||||
(c,s) <- get
|
(c,s) <- get
|
||||||
@ -952,14 +950,15 @@ instance ( RegisterInfo r
|
|||||||
seq s' $ put $ (True,s')
|
seq s' $ put $ (True,s')
|
||||||
return $! zr
|
return $! zr
|
||||||
z_stk <- absStackJoinD x_stk y_stk
|
z_stk <- absStackJoinD x_stk y_stk
|
||||||
return $ AbsBlockState { _absRegState = z_regs
|
z_bnds <-
|
||||||
, _startAbsStack = z_stk
|
case joinInitialBounds (x^.initIndexBounds) (y^.initIndexBounds) of
|
||||||
}
|
Just z_bnds -> (_1 .= True) $> z_bnds
|
||||||
|
Nothing -> pure (x^.initIndexBounds)
|
||||||
|
|
||||||
z = traceUnless (Set.null dropped)
|
return $ AbsBlockState { _absRegState = z_regs
|
||||||
("dropped abs " ++ show (ppSegAddrSet dropped) ++ "\n"
|
, _startAbsStack = z_stk
|
||||||
++ show x ++ "\n" ++ show y) $
|
, _initIndexBounds = z_bnds
|
||||||
zs
|
}
|
||||||
|
|
||||||
instance ( ShowF r
|
instance ( ShowF r
|
||||||
) => Pretty (AbsBlockState r) where
|
) => Pretty (AbsBlockState r) where
|
||||||
@ -1000,10 +999,7 @@ type ArchAbsValue arch = AbsValue (RegAddrWidth (ArchReg arch))
|
|||||||
|
|
||||||
-- | This stores the abstract state of the system at a given point in time.
|
-- | This stores the abstract state of the system at a given point in time.
|
||||||
data AbsProcessorState r ids
|
data AbsProcessorState r ids
|
||||||
= AbsProcessorState { absCodeWidth :: !(NatRepr (RegAddrWidth r))
|
= AbsProcessorState { absMem :: !(Memory (RegAddrWidth r))
|
||||||
-- ^ The width of a code pointer; the 'NatRepr' type
|
|
||||||
-- connects the type-level nat with the value
|
|
||||||
, absMem :: !(Memory (RegAddrWidth r))
|
|
||||||
-- ^ Recognizer for code addresses.
|
-- ^ Recognizer for code addresses.
|
||||||
, _absInitialRegs
|
, _absInitialRegs
|
||||||
:: !(RegState r (AbsValue (RegAddrWidth r)))
|
:: !(RegState r (AbsValue (RegAddrWidth r)))
|
||||||
@ -1013,8 +1009,13 @@ data AbsProcessorState r ids
|
|||||||
-- symbolic values associated with them
|
-- symbolic values associated with them
|
||||||
, _curAbsStack :: !(AbsBlockStack (RegAddrWidth r))
|
, _curAbsStack :: !(AbsBlockStack (RegAddrWidth r))
|
||||||
-- ^ The current symbolic state of the stack
|
-- ^ The current symbolic state of the stack
|
||||||
|
, _indexBounds :: !(IndexBounds r ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | The width of an address
|
||||||
|
absCodeWidth :: AbsProcessorState r ids -> NatRepr (RegAddrWidth r)
|
||||||
|
absCodeWidth = memWidth . absMem
|
||||||
|
|
||||||
absInitialRegs :: Simple Lens (AbsProcessorState r ids)
|
absInitialRegs :: Simple Lens (AbsProcessorState r ids)
|
||||||
(RegState r (AbsValue (RegAddrWidth r)))
|
(RegState r (AbsValue (RegAddrWidth r)))
|
||||||
absInitialRegs = lens _absInitialRegs (\s v -> s { _absInitialRegs = v })
|
absInitialRegs = lens _absInitialRegs (\s v -> s { _absInitialRegs = v })
|
||||||
@ -1026,6 +1027,10 @@ absAssignments = lens _absAssignments (\s v -> s { _absAssignments = v })
|
|||||||
curAbsStack :: Simple Lens (AbsProcessorState r ids) (AbsBlockStack (RegAddrWidth r))
|
curAbsStack :: Simple Lens (AbsProcessorState r ids) (AbsBlockStack (RegAddrWidth r))
|
||||||
curAbsStack = lens _curAbsStack (\s v -> s { _curAbsStack = v })
|
curAbsStack = lens _curAbsStack (\s v -> s { _curAbsStack = v })
|
||||||
|
|
||||||
|
-- | Return the index
|
||||||
|
indexBounds :: Simple Lens (AbsProcessorState r ids) (IndexBounds r ids)
|
||||||
|
indexBounds = lens _indexBounds (\s v -> s { _indexBounds = v })
|
||||||
|
|
||||||
instance ShowF r
|
instance ShowF r
|
||||||
=> Show (AbsProcessorState r ids) where
|
=> Show (AbsProcessorState r ids) where
|
||||||
show = show . pretty
|
show = show . pretty
|
||||||
@ -1033,22 +1038,27 @@ instance ShowF r
|
|||||||
-- FIXME
|
-- FIXME
|
||||||
instance (ShowF r)
|
instance (ShowF r)
|
||||||
=> Pretty (AbsProcessorState r ids) where
|
=> Pretty (AbsProcessorState r ids) where
|
||||||
pretty regs = pretty (AbsBlockState { _absRegState = regs ^. absInitialRegs
|
pretty s =
|
||||||
, _startAbsStack = regs ^. curAbsStack })
|
text "registers:" <$$>
|
||||||
|
indent 2 (pretty (s^.absInitialRegs)) <$$>
|
||||||
|
stack_d
|
||||||
|
where stack = s^.curAbsStack
|
||||||
|
stack_d | Map.null stack = empty
|
||||||
|
| otherwise = text "stack:" <$$>
|
||||||
|
indent 2 (ppAbsStack stack)
|
||||||
|
|
||||||
initAbsProcessorState :: NatRepr (RegAddrWidth r)
|
initAbsProcessorState :: Memory (RegAddrWidth r)
|
||||||
-> Memory (RegAddrWidth r)
|
|
||||||
-- ^ Current state of memory in the processor.
|
-- ^ Current state of memory in the processor.
|
||||||
--
|
--
|
||||||
-- Used for checking code segment status.
|
-- Used for checking code segment status.
|
||||||
-> AbsBlockState r
|
-> AbsBlockState r
|
||||||
-> AbsProcessorState r ids
|
-> AbsProcessorState r ids
|
||||||
initAbsProcessorState code_width mem s =
|
initAbsProcessorState mem s =
|
||||||
AbsProcessorState { absCodeWidth = code_width
|
AbsProcessorState { absMem = mem
|
||||||
, absMem = mem
|
|
||||||
, _absInitialRegs = s^.absRegState
|
, _absInitialRegs = s^.absRegState
|
||||||
, _absAssignments = MapF.empty
|
, _absAssignments = MapF.empty
|
||||||
, _curAbsStack = s^.startAbsStack
|
, _curAbsStack = s^.startAbsStack
|
||||||
|
, _indexBounds = mkIndexBounds (s^.initIndexBounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | A lens that allows one to lookup and update the value of an assignment in
|
-- | A lens that allows one to lookup and update the value of an assignment in
|
||||||
@ -1178,18 +1188,6 @@ addMemWrite cur_ip a v r =
|
|||||||
-- FIXME: nuke stack on an unknown address or Top?
|
-- FIXME: nuke stack on an unknown address or Top?
|
||||||
_ -> r
|
_ -> r
|
||||||
|
|
||||||
-- subOff :: NatRepr w -> Integer -> Integer -> Integer
|
|
||||||
-- subOff w o v = toUnsigned w (o - v)
|
|
||||||
|
|
||||||
mkAbsBlockState :: RegisterInfo r
|
|
||||||
=> (forall tp . r tp -> AbsValue (RegAddrWidth r) tp)
|
|
||||||
-> AbsBlockStack (RegAddrWidth r)
|
|
||||||
-> AbsBlockState r
|
|
||||||
mkAbsBlockState trans newStack =
|
|
||||||
AbsBlockState { _absRegState = mkRegState trans
|
|
||||||
, _startAbsStack = newStack
|
|
||||||
}
|
|
||||||
|
|
||||||
absStackHasReturnAddr :: AbsBlockState r -> Bool
|
absStackHasReturnAddr :: AbsBlockState r -> Bool
|
||||||
absStackHasReturnAddr s = isJust $ find isReturnAddr (Map.elems (s^.startAbsStack))
|
absStackHasReturnAddr s = isJust $ find isReturnAddr (Map.elems (s^.startAbsStack))
|
||||||
where isReturnAddr (StackEntry _ ReturnAddr) = True
|
where isReturnAddr (StackEntry _ ReturnAddr) = True
|
||||||
@ -1203,11 +1201,15 @@ finalAbsBlockState :: forall a ids
|
|||||||
)
|
)
|
||||||
=> AbsProcessorState (ArchReg a) ids
|
=> AbsProcessorState (ArchReg a) ids
|
||||||
-> RegState (ArchReg a) (Value a ids)
|
-> RegState (ArchReg a) (Value a ids)
|
||||||
|
-- ^ Final values for abstract processor state
|
||||||
-> AbsBlockState (ArchReg a)
|
-> AbsBlockState (ArchReg a)
|
||||||
finalAbsBlockState c s =
|
finalAbsBlockState c s =
|
||||||
let transferReg :: ArchReg a tp -> ArchAbsValue a tp
|
let transferReg :: ArchReg a tp -> ArchAbsValue a tp
|
||||||
transferReg r = transferValue c (s^.boundValue r)
|
transferReg r = transferValue c (s^.boundValue r)
|
||||||
in mkAbsBlockState transferReg (c^.curAbsStack)
|
in AbsBlockState { _absRegState = mkRegState transferReg
|
||||||
|
, _startAbsStack = c^.curAbsStack
|
||||||
|
, _initIndexBounds = nextBlockBounds s (c^.indexBounds)
|
||||||
|
}
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Transfer functions
|
-- Transfer functions
|
||||||
@ -1229,3 +1231,41 @@ transferApp r a =
|
|||||||
BVAnd w x y -> bitop (.&.) w (transferValue r x) (transferValue r y)
|
BVAnd w x y -> bitop (.&.) w (transferValue r x) (transferValue r y)
|
||||||
BVOr w x y -> bitop (.|.) w (transferValue r x) (transferValue r y)
|
BVOr w x y -> bitop (.|.) w (transferValue r x) (transferValue r y)
|
||||||
_ -> TopV
|
_ -> TopV
|
||||||
|
|
||||||
|
-- | Minimal information needed to parse a function call/system call
|
||||||
|
data CallParams (r :: Type -> *)
|
||||||
|
= CallParams { postCallStackDelta :: Integer
|
||||||
|
-- ^ Amount stack should shift by when going before/after call.
|
||||||
|
, preserveReg :: forall tp . r tp -> Bool
|
||||||
|
-- ^ Return true if a register value is preserved by a call.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Return state post call
|
||||||
|
postCallAbsState :: forall r
|
||||||
|
. ( RegisterInfo r
|
||||||
|
, HasRepr r TypeRepr
|
||||||
|
)
|
||||||
|
=> CallParams r
|
||||||
|
-> AbsBlockState r
|
||||||
|
-> SegmentedAddr (RegAddrWidth r)
|
||||||
|
-- ^ Address we are jumping to
|
||||||
|
-> AbsBlockState r
|
||||||
|
postCallAbsState params ab0 addr =
|
||||||
|
AbsBlockState { _absRegState = mkRegState regFn
|
||||||
|
, _startAbsStack = ab0^.startAbsStack
|
||||||
|
, _initIndexBounds = arbitraryInitialBounds
|
||||||
|
}
|
||||||
|
where regFn :: r tp -> AbsValue (RegAddrWidth r) tp
|
||||||
|
regFn r
|
||||||
|
-- We set IPReg
|
||||||
|
| 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)))
|
||||||
|
-- Copy callee saved registers
|
||||||
|
| preserveReg params r =
|
||||||
|
ab0^.absRegState^.boundValue r
|
||||||
|
-- We know nothing about other registers.
|
||||||
|
| otherwise =
|
||||||
|
TopV
|
||||||
|
@ -5,12 +5,15 @@ Maintainer : jhendrix@galois.com
|
|||||||
This defines the architecture-specific information needed for code discovery.
|
This defines the architecture-specific information needed for code discovery.
|
||||||
-}
|
-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE GADTs #-}
|
{-# LANGUAGE GADTs #-}
|
||||||
{-# LANGUAGE RankNTypes #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
module Data.Macaw.Architecture.Info
|
module Data.Macaw.Architecture.Info
|
||||||
( ArchitectureInfo(..)
|
( ArchitectureInfo(..)
|
||||||
, ReadAddrFn
|
, ReadAddrFn
|
||||||
, DisassembleFn
|
, DisassembleFn
|
||||||
|
, archPostCallAbsState
|
||||||
|
, archPostSyscallAbsState
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.ST
|
import Control.Monad.ST
|
||||||
@ -19,6 +22,7 @@ import Data.Parameterized.Nonce
|
|||||||
import Data.Macaw.AbsDomain.AbsState
|
import Data.Macaw.AbsDomain.AbsState
|
||||||
import Data.Macaw.CFG
|
import Data.Macaw.CFG
|
||||||
import Data.Macaw.Memory
|
import Data.Macaw.Memory
|
||||||
|
import Data.Macaw.Types
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- ArchitectureInfo
|
-- ArchitectureInfo
|
||||||
@ -66,26 +70,46 @@ data ArchitectureInfo arch
|
|||||||
-- ^ The shift that the stack moves with a call.
|
-- ^ The shift that the stack moves with a call.
|
||||||
, disassembleFn :: !(DisassembleFn arch)
|
, disassembleFn :: !(DisassembleFn arch)
|
||||||
-- ^ Function for disasembling a block.
|
-- ^ Function for disasembling a block.
|
||||||
|
, preserveRegAcrossCall :: !(forall tp . ArchReg arch tp -> Bool)
|
||||||
|
-- ^ Return true if architecture register should be preserved across a call.
|
||||||
|
, preserveRegAcrossSyscall :: !(forall tp . ArchReg arch tp -> Bool)
|
||||||
|
-- ^ Return true if architecture register should be preserved across a system call.
|
||||||
, fnBlockStateFn :: !(Memory (RegAddrWidth (ArchReg arch))
|
, fnBlockStateFn :: !(Memory (RegAddrWidth (ArchReg arch))
|
||||||
-> SegmentedAddr (RegAddrWidth (ArchReg arch))
|
-> SegmentedAddr (RegAddrWidth (ArchReg arch))
|
||||||
-> AbsBlockState (ArchReg arch))
|
-> AbsBlockState (ArchReg arch))
|
||||||
-- ^ Creates an abstract block state for representing the beginning of a
|
-- ^ Creates an abstract block state for representing the beginning of a
|
||||||
-- function.
|
-- function.
|
||||||
, postSyscallFn :: !(AbsBlockState (ArchReg arch)
|
|
||||||
-> ArchSegmentedAddr arch
|
|
||||||
-> AbsBlockState (ArchReg arch))
|
|
||||||
-- ^ Transfer function that maps abstract state before system call to
|
|
||||||
-- abstract state after system call.
|
|
||||||
--
|
|
||||||
-- The first argument contains the first abstract state, and the
|
|
||||||
-- second contains the address that we are jumping to.
|
|
||||||
, postCallAbsStateFn :: !(AbsBlockState (ArchReg arch)
|
|
||||||
-> ArchSegmentedAddr arch
|
|
||||||
-> AbsBlockState (ArchReg arch))
|
|
||||||
-- ^ Abstract state after a function call.
|
|
||||||
, absEvalArchFn :: !(forall ids tp
|
, absEvalArchFn :: !(forall ids tp
|
||||||
. AbsProcessorState (ArchReg arch) ids
|
. AbsProcessorState (ArchReg arch) ids
|
||||||
-> ArchFn arch ids tp
|
-> ArchFn arch ids tp
|
||||||
-> AbsValue (RegAddrWidth (ArchReg arch)) tp)
|
-> AbsValue (RegAddrWidth (ArchReg arch)) tp)
|
||||||
-- ^ Evaluates an architecture-specific function
|
-- ^ Evaluates an architecture-specific function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Return state post call
|
||||||
|
archPostCallAbsState :: ( RegisterInfo (ArchReg arch)
|
||||||
|
, HasRepr (ArchReg arch) TypeRepr
|
||||||
|
)
|
||||||
|
=> ArchitectureInfo arch
|
||||||
|
-- ^ Architecture information
|
||||||
|
-> AbsBlockState (ArchReg arch)
|
||||||
|
-> SegmentedAddr (RegAddrWidth (ArchReg arch))
|
||||||
|
-> AbsBlockState (ArchReg arch)
|
||||||
|
archPostCallAbsState archInfo = postCallAbsState params
|
||||||
|
where params = CallParams { postCallStackDelta = negate (callStackDelta archInfo)
|
||||||
|
, preserveReg = preserveRegAcrossCall archInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Return state post call
|
||||||
|
archPostSyscallAbsState :: ( RegisterInfo (ArchReg arch)
|
||||||
|
, HasRepr (ArchReg arch) TypeRepr
|
||||||
|
)
|
||||||
|
=> ArchitectureInfo arch
|
||||||
|
-- ^ Architecture information
|
||||||
|
-> AbsBlockState (ArchReg arch)
|
||||||
|
-> SegmentedAddr (RegAddrWidth (ArchReg arch))
|
||||||
|
-> AbsBlockState (ArchReg arch)
|
||||||
|
archPostSyscallAbsState archInfo = postCallAbsState params
|
||||||
|
where params = CallParams { postCallStackDelta = 0
|
||||||
|
, preserveReg = preserveRegAcrossSyscall archInfo
|
||||||
|
}
|
||||||
|
@ -25,7 +25,6 @@ data SyscallArgType = VoidArgType | WordArgType
|
|||||||
type SyscallTypeInfo = (String, SyscallArgType, [SyscallArgType])
|
type SyscallTypeInfo = (String, SyscallArgType, [SyscallArgType])
|
||||||
|
|
||||||
data SyscallPersonality arch =
|
data SyscallPersonality arch =
|
||||||
SyscallPersonality { spName :: String
|
SyscallPersonality { spTypeInfo :: Map.Map Word64 SyscallTypeInfo
|
||||||
, spTypeInfo :: Map.Map Word64 SyscallTypeInfo
|
|
||||||
, spResultRegisters :: [Some (ArchReg arch)]
|
, spResultRegisters :: [Some (ArchReg arch)]
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ module Data.Macaw.CFG
|
|||||||
, foldApp
|
, foldApp
|
||||||
, traverseApp
|
, traverseApp
|
||||||
-- * RegState
|
-- * RegState
|
||||||
, RegState(..)
|
, RegState
|
||||||
, boundValue
|
, boundValue
|
||||||
, cmpRegState
|
, cmpRegState
|
||||||
, curIP
|
, curIP
|
||||||
@ -750,7 +750,7 @@ data Value arch ids tp
|
|||||||
-- ^ A constant bitvector
|
-- ^ A constant bitvector
|
||||||
| ( tp ~ BVType (ArchAddrWidth arch))
|
| ( tp ~ BVType (ArchAddrWidth arch))
|
||||||
=> RelocatableValue !(NatRepr (ArchAddrWidth arch)) !(ArchSegmentedAddr arch)
|
=> RelocatableValue !(NatRepr (ArchAddrWidth arch)) !(ArchSegmentedAddr arch)
|
||||||
-- ^ A value that can be relocated.
|
-- ^ A given memory address.
|
||||||
| AssignedValue !(Assignment arch ids tp)
|
| AssignedValue !(Assignment arch ids tp)
|
||||||
-- ^ Value from an assignment statement.
|
-- ^ Value from an assignment statement.
|
||||||
| Initial !(ArchReg arch tp)
|
| Initial !(ArchReg arch tp)
|
||||||
@ -995,13 +995,14 @@ asBaseOffset x
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- RegState
|
-- RegState
|
||||||
|
|
||||||
-- | This represents the state of the processor registers after some
|
-- | This represents the state of the processor registers.
|
||||||
-- execution.
|
newtype RegState (r :: k -> *) (f :: k -> *) = RegState (MapF.MapF r f)
|
||||||
newtype RegState (r :: k -> *) (f :: k -> *) = RegState (MapF.MapF r f)
|
|
||||||
-- deriving (FunctorF, FoldableF)
|
|
||||||
|
|
||||||
deriving instance FunctorF (RegState r)
|
deriving instance (OrdF r, EqF f) => Eq (RegState r f)
|
||||||
|
|
||||||
|
deriving instance FunctorF (RegState r)
|
||||||
deriving instance FoldableF (RegState r)
|
deriving instance FoldableF (RegState r)
|
||||||
|
|
||||||
instance TraversableF (RegState r) where
|
instance TraversableF (RegState r) where
|
||||||
traverseF f (RegState m) = RegState <$> traverseF f m
|
traverseF f (RegState m) = RegState <$> traverseF f m
|
||||||
|
|
||||||
@ -1024,11 +1025,11 @@ boundValue r = lens getter setter
|
|||||||
Nothing -> error "internal error in boundValue given unexpected reg"
|
Nothing -> error "internal error in boundValue given unexpected reg"
|
||||||
setter (RegState m) v = RegState (MapF.insert r v m)
|
setter (RegState m) v = RegState (MapF.insert r v m)
|
||||||
|
|
||||||
instance (OrdF r, EqF f) => Eq (RegState r f) where
|
|
||||||
s == s' = cmpRegState eqF s s'
|
|
||||||
|
|
||||||
|
-- | Compares if two register states are equal.
|
||||||
cmpRegState :: OrdF r
|
cmpRegState :: OrdF r
|
||||||
=> (forall u. f u -> g u -> Bool)
|
=> (forall u. f u -> g u -> Bool)
|
||||||
|
-- ^ Function for checking if two values are equal.
|
||||||
-> RegState r f
|
-> RegState r f
|
||||||
-> RegState r g
|
-> RegState r g
|
||||||
-> Bool
|
-> Bool
|
||||||
|
@ -52,10 +52,10 @@ import Data.Macaw.AbsDomain.AbsState
|
|||||||
import Data.Macaw.AbsDomain.Refine
|
import Data.Macaw.AbsDomain.Refine
|
||||||
import qualified Data.Macaw.AbsDomain.StridedInterval as SI
|
import qualified Data.Macaw.AbsDomain.StridedInterval as SI
|
||||||
import Data.Macaw.Architecture.Info
|
import Data.Macaw.Architecture.Info
|
||||||
import Data.Macaw.Architecture.Syscall
|
|
||||||
import Data.Macaw.CFG
|
import Data.Macaw.CFG
|
||||||
import Data.Macaw.DebugLogging
|
import Data.Macaw.DebugLogging
|
||||||
import Data.Macaw.Discovery.Info
|
import Data.Macaw.Discovery.Info
|
||||||
|
--import Data.Macaw.Discovery.JumpBounds
|
||||||
import Data.Macaw.Memory
|
import Data.Macaw.Memory
|
||||||
import qualified Data.Macaw.Memory.Permissions as Perm
|
import qualified Data.Macaw.Memory.Permissions as Perm
|
||||||
import Data.Macaw.Types
|
import Data.Macaw.Types
|
||||||
@ -184,14 +184,12 @@ runCFGM :: ArchitectureInfo arch
|
|||||||
-- ^ Memory to use when decoding instructions.
|
-- ^ Memory to use when decoding instructions.
|
||||||
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
||||||
-- ^ Names for (some) function entry points
|
-- ^ Names for (some) function entry points
|
||||||
-> SyscallPersonality arch
|
|
||||||
-- ^ Syscall personality
|
|
||||||
-> (forall ids . CFGM arch ids ())
|
-> (forall ids . CFGM arch ids ())
|
||||||
-- ^ Computation to run.
|
-- ^ Computation to run.
|
||||||
-> Some (DiscoveryInfo arch)
|
-> Some (DiscoveryInfo arch)
|
||||||
runCFGM arch_info mem symbols sysp m = do
|
runCFGM arch_info mem symbols m = do
|
||||||
withGlobalSTNonceGenerator $ \nonce_gen -> do
|
withGlobalSTNonceGenerator $ \nonce_gen -> do
|
||||||
let init_info = emptyDiscoveryInfo nonce_gen mem symbols sysp arch_info
|
let init_info = emptyDiscoveryInfo nonce_gen mem symbols arch_info
|
||||||
Some <$> execStateT (unCFGM m) init_info
|
Some <$> execStateT (unCFGM m) init_info
|
||||||
|
|
||||||
printAddrBacktrace :: Map (ArchSegmentedAddr arch) (BlockRegion arch ids)
|
printAddrBacktrace :: Map (ArchSegmentedAddr arch) (BlockRegion arch ids)
|
||||||
@ -300,8 +298,8 @@ markCodeAddrBlock rsn addr ab = do
|
|||||||
-- Get block for addr
|
-- Get block for addr
|
||||||
tryDisassembleAddr rsn addr ab
|
tryDisassembleAddr rsn addr ab
|
||||||
-- Get block for old block
|
-- Get block for old block
|
||||||
let Just old_ab = Map.lookup l (s^.absState)
|
let Just old_code_info = Map.lookup l (s^.codeInfoMap)
|
||||||
tryDisassembleAddr (brReason br) l old_ab
|
tryDisassembleAddr (brReason br) l (old_code_info^.addrAbsBlockState)
|
||||||
-- Add function starts to split to frontier
|
-- Add function starts to split to frontier
|
||||||
-- This will result in us re-exploring l_start and a_start
|
-- This will result in us re-exploring l_start and a_start
|
||||||
-- once the current function is done.
|
-- once the current function is done.
|
||||||
@ -365,9 +363,12 @@ markAddrAsFunction rsn addr = do
|
|||||||
-- Get abstract state associated with function begining at address
|
-- Get abstract state associated with function begining at address
|
||||||
let abstState = fnBlockStateFn (archInfo s) mem addr
|
let abstState = fnBlockStateFn (archInfo s) mem addr
|
||||||
markCodeAddrBlock rsn addr abstState
|
markCodeAddrBlock rsn addr abstState
|
||||||
modify $ \s0 -> s0 & absState %~ Map.insert addr abstState
|
let cInfo = CodeInfo { _addrAbsBlockState = abstState
|
||||||
|
}
|
||||||
|
modify $ \s0 -> s0 & codeInfoMap %~ Map.insert addr cInfo
|
||||||
& functionEntries %~ Set.insert addr
|
& functionEntries %~ Set.insert addr
|
||||||
& function_frontier %~ maybeMapInsert low (SplitAt addr) . Map.insert addr rsn
|
& function_frontier %~ maybeMapInsert low (SplitAt addr)
|
||||||
|
. Map.insert addr rsn
|
||||||
|
|
||||||
maybeMapInsert :: Ord a => Maybe a -> b -> Map a b -> Map a b
|
maybeMapInsert :: Ord a => Maybe a -> b -> Map a b -> Map a b
|
||||||
maybeMapInsert mk v = maybe id (\k -> Map.insert k v) mk
|
maybeMapInsert mk v = maybe id (\k -> Map.insert k v) mk
|
||||||
@ -412,7 +413,7 @@ assignmentAbsValues :: forall arch ids
|
|||||||
=> ArchitectureInfo arch
|
=> ArchitectureInfo arch
|
||||||
-> Memory (ArchAddrWidth arch)
|
-> Memory (ArchAddrWidth arch)
|
||||||
-> CFG arch ids
|
-> CFG arch ids
|
||||||
-> AbsStateMap arch
|
-> Map (ArchSegmentedAddr arch) (CodeInfo arch)
|
||||||
-> MapF (AssignId ids) (ArchAbsValue arch)
|
-> MapF (AssignId ids) (ArchAbsValue arch)
|
||||||
assignmentAbsValues info mem g absm =
|
assignmentAbsValues info mem g absm =
|
||||||
foldl' go MapF.empty (Map.elems (g^.cfgBlocks))
|
foldl' go MapF.empty (Map.elems (g^.cfgBlocks))
|
||||||
@ -422,10 +423,12 @@ assignmentAbsValues info mem g absm =
|
|||||||
go m0 b =
|
go m0 b =
|
||||||
case blockLabel b of
|
case blockLabel b of
|
||||||
GeneratedBlock a 0 -> do
|
GeneratedBlock a 0 -> do
|
||||||
let w = addrWidthNatRepr (archAddrWidth info)
|
case Map.lookup a absm of
|
||||||
let Just ab = Map.lookup a absm
|
Nothing -> do
|
||||||
let abs_state = initAbsProcessorState w mem ab
|
error $ "assignmentAbsValues could not find code infomation for block " ++ show a
|
||||||
insBlock b abs_state m0
|
Just codeInfo -> do
|
||||||
|
let abs_state = initAbsProcessorState mem (codeInfo^.addrAbsBlockState)
|
||||||
|
insBlock b abs_state m0
|
||||||
_ -> m0
|
_ -> m0
|
||||||
|
|
||||||
insBlock :: Block arch ids
|
insBlock :: Block arch ids
|
||||||
@ -471,19 +474,21 @@ mergeIntraJump src ab tgt = do
|
|||||||
let upd new s = do
|
let upd new s = do
|
||||||
-- Add reverse edge
|
-- Add reverse edge
|
||||||
s & reverseEdges %~ Map.insertWith Set.union tgt (Set.singleton (labelAddr src))
|
s & reverseEdges %~ Map.insertWith Set.union tgt (Set.singleton (labelAddr src))
|
||||||
& absState %~ Map.insert tgt new
|
& codeInfoMap %~ Map.insert tgt new
|
||||||
& frontier %~ Map.insert tgt rsn
|
& frontier %~ Map.insert tgt rsn
|
||||||
s0 <- get
|
s0 <- get
|
||||||
case Map.lookup tgt (s0^.absState) of
|
let cinfo_new = CodeInfo { _addrAbsBlockState = ab
|
||||||
|
}
|
||||||
|
case Map.lookup tgt (s0^.codeInfoMap) of
|
||||||
-- We have seen this block before, so need to join and see if
|
-- We have seen this block before, so need to join and see if
|
||||||
-- the results is changed.
|
-- the results is changed.
|
||||||
Just ab_old ->
|
Just cinfo_old ->
|
||||||
case joinD ab_old ab of
|
case unionCodeInfo cinfo_old cinfo_new of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just new -> modify $ upd new
|
Just new -> modify $ upd new
|
||||||
-- We haven't seen this block before
|
-- We haven't seen this block before
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
modify $ upd ab
|
modify $ upd cinfo_new
|
||||||
markCodeAddrBlock rsn tgt ab
|
markCodeAddrBlock rsn tgt ab
|
||||||
|
|
||||||
-- -----------------------------------------------------------------------------
|
-- -----------------------------------------------------------------------------
|
||||||
@ -563,7 +568,7 @@ fetchAndExecute b regs' s' = do
|
|||||||
let abst = finalAbsBlockState regs' s'
|
let abst = finalAbsBlockState regs' s'
|
||||||
seq abst $ do
|
seq abst $ do
|
||||||
-- Merge caller return information
|
-- Merge caller return information
|
||||||
mergeIntraJump lbl (postCallAbsStateFn arch_info abst ret) ret
|
mergeIntraJump lbl (archPostCallAbsState arch_info abst ret) ret
|
||||||
-- Look for new ips.
|
-- Look for new ips.
|
||||||
let addrs = concretizeAbsCodePointers mem (abst^.absRegState^.curIP)
|
let addrs = concretizeAbsCodePointers mem (abst^.absRegState^.curIP)
|
||||||
mapM_ (markAddrAsFunction (CallTarget src)) addrs
|
mapM_ (markAddrAsFunction (CallTarget src)) addrs
|
||||||
@ -629,7 +634,10 @@ fetchAndExecute b regs' s' = do
|
|||||||
mapM_ (recordWriteStmt src regs') (blockStmts b)
|
mapM_ (recordWriteStmt src regs') (blockStmts b)
|
||||||
|
|
||||||
-- Try to compute jump table bounds
|
-- Try to compute jump table bounds
|
||||||
let mread_end = getJumpTableBounds regs' base jump_idx
|
read_end <-
|
||||||
|
case getJumpTableBounds regs' base jump_idx of
|
||||||
|
Just e -> pure e
|
||||||
|
Nothing -> error $ "Could not compute jump bounds."
|
||||||
|
|
||||||
let abst :: AbsBlockState (ArchReg arch)
|
let abst :: AbsBlockState (ArchReg arch)
|
||||||
abst = finalAbsBlockState regs' s'
|
abst = finalAbsBlockState regs' s'
|
||||||
@ -644,7 +652,7 @@ fetchAndExecute b regs' s' = do
|
|||||||
-> ArchAddr arch
|
-> ArchAddr arch
|
||||||
-- /\ Current index
|
-- /\ Current index
|
||||||
-> CFGM arch ids [ArchSegmentedAddr arch]
|
-> CFGM arch ids [ArchSegmentedAddr arch]
|
||||||
resolveJump prev idx | Just idx == mread_end = do
|
resolveJump prev idx | idx == read_end = do
|
||||||
-- Stop jump table when we have reached computed bounds.
|
-- Stop jump table when we have reached computed bounds.
|
||||||
return (reverse prev)
|
return (reverse prev)
|
||||||
resolveJump prev idx = do
|
resolveJump prev idx = do
|
||||||
@ -660,7 +668,7 @@ fetchAndExecute b regs' s' = do
|
|||||||
mergeIntraJump lbl abst' tgt_addr
|
mergeIntraJump lbl abst' tgt_addr
|
||||||
resolveJump (tgt_addr:prev) (idx+1)
|
resolveJump (tgt_addr:prev) (idx+1)
|
||||||
_ -> do
|
_ -> do
|
||||||
debug DCFG ("Stop jump table: " ++ show idx ++ " " ++ show mread_end) $ do
|
debug DCFG ("Stop jump table: " ++ show idx ++ " " ++ show read_end) $ do
|
||||||
return (reverse prev)
|
return (reverse prev)
|
||||||
read_addrs <- resolveJump [] 0
|
read_addrs <- resolveJump [] 0
|
||||||
let last_index = fromIntegral (length read_addrs)
|
let last_index = fromIntegral (length read_addrs)
|
||||||
@ -696,7 +704,6 @@ transferBlock :: TransferConstraints arch
|
|||||||
transferBlock b regs = do
|
transferBlock b regs = do
|
||||||
let lbl = blockLabel b
|
let lbl = blockLabel b
|
||||||
let src = labelAddr lbl
|
let src = labelAddr lbl
|
||||||
debugM DCFG ("transferBlock " ++ show lbl)
|
|
||||||
mem <- gets memory
|
mem <- gets memory
|
||||||
arch_info <- gets archInfo
|
arch_info <- gets archInfo
|
||||||
let regs' = transferStmts arch_info regs (blockStmts b)
|
let regs' = transferStmts arch_info regs (blockStmts b)
|
||||||
@ -722,7 +729,7 @@ transferBlock b regs = do
|
|||||||
let ips = concretizeAbsCodePointers mem (abst^.absRegState^.curIP)
|
let ips = concretizeAbsCodePointers mem (abst^.absRegState^.curIP)
|
||||||
-- Merge system call result with possible next IPs.
|
-- Merge system call result with possible next IPs.
|
||||||
Fold.forM_ ips $ \addr -> do
|
Fold.forM_ ips $ \addr -> do
|
||||||
mergeIntraJump lbl (postSyscallFn arch_info abst addr) addr
|
mergeIntraJump lbl (archPostSyscallAbsState arch_info abst addr) addr
|
||||||
|
|
||||||
FetchAndExecute s' -> do
|
FetchAndExecute s' -> do
|
||||||
fetchAndExecute b regs' s'
|
fetchAndExecute b regs' s'
|
||||||
@ -739,13 +746,12 @@ transfer addr = do
|
|||||||
case mroot of
|
case mroot of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
Just root -> do
|
Just root -> do
|
||||||
addrWidth <- gets $ addrWidthNatRepr . archAddrWidth . archInfo
|
minfo <- use $ codeInfoMap . at addr
|
||||||
mab <- uses absState $ Map.lookup addr
|
case minfo of
|
||||||
case mab of
|
|
||||||
Nothing -> error $ "Could not find block " ++ show addr ++ "."
|
Nothing -> error $ "Could not find block " ++ show addr ++ "."
|
||||||
Just ab -> do
|
Just info -> do
|
||||||
transferBlock root $
|
transferBlock root $
|
||||||
initAbsProcessorState addrWidth mem ab
|
initAbsProcessorState mem (info^.addrAbsBlockState)
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- Main loop
|
-- Main loop
|
||||||
@ -765,7 +771,7 @@ explore_frontier = do
|
|||||||
-- Delete any entries we previously discovered for function.
|
-- Delete any entries we previously discovered for function.
|
||||||
& reverseEdges %~ deleteMapRange (Just addr) high
|
& reverseEdges %~ deleteMapRange (Just addr) high
|
||||||
-- Delete any entries we previously discovered for function.
|
-- Delete any entries we previously discovered for function.
|
||||||
& absState %~ deleteMapRange (Just addr) high
|
& codeInfoMap %~ deleteMapRange (Just addr) high
|
||||||
put st'
|
put st'
|
||||||
explore_frontier
|
explore_frontier
|
||||||
Just ((addr,_rsn), next_roots) -> do
|
Just ((addr,_rsn), next_roots) -> do
|
||||||
@ -789,8 +795,6 @@ cfgFromAddrs :: forall arch
|
|||||||
-- ^ Memory to use when decoding instructions.
|
-- ^ Memory to use when decoding instructions.
|
||||||
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
||||||
-- ^ Names for (some) function entry points
|
-- ^ Names for (some) function entry points
|
||||||
-> SyscallPersonality arch
|
|
||||||
-- ^ Syscall personality
|
|
||||||
-> [ArchSegmentedAddr arch]
|
-> [ArchSegmentedAddr arch]
|
||||||
-- ^ Initial function entry points.
|
-- ^ Initial function entry points.
|
||||||
-> [(ArchSegmentedAddr arch, ArchSegmentedAddr arch)]
|
-> [(ArchSegmentedAddr arch, ArchSegmentedAddr arch)]
|
||||||
@ -799,8 +803,8 @@ cfgFromAddrs :: forall arch
|
|||||||
--
|
--
|
||||||
-- Each entry contains an address and the value stored in it.
|
-- Each entry contains an address and the value stored in it.
|
||||||
-> Some (DiscoveryInfo arch)
|
-> Some (DiscoveryInfo arch)
|
||||||
cfgFromAddrs arch_info mem symbols sysp init_addrs mem_words =
|
cfgFromAddrs arch_info mem symbols init_addrs mem_words =
|
||||||
runCFGM arch_info mem symbols sysp $ do
|
runCFGM arch_info mem symbols $ do
|
||||||
-- Set abstract state for initial functions
|
-- Set abstract state for initial functions
|
||||||
mapM_ (markAddrAsFunction InitAddr) init_addrs
|
mapM_ (markAddrAsFunction InitAddr) init_addrs
|
||||||
explore_frontier
|
explore_frontier
|
||||||
|
@ -23,7 +23,6 @@ module Data.Macaw.Discovery.Info
|
|||||||
-- * The interpreter state
|
-- * The interpreter state
|
||||||
, DiscoveryInfo
|
, DiscoveryInfo
|
||||||
, emptyDiscoveryInfo
|
, emptyDiscoveryInfo
|
||||||
, syscallPersonality
|
|
||||||
, nonceGen
|
, nonceGen
|
||||||
, archInfo
|
, archInfo
|
||||||
, memory
|
, memory
|
||||||
@ -39,8 +38,10 @@ module Data.Macaw.Discovery.Info
|
|||||||
, frontier
|
, frontier
|
||||||
, function_frontier
|
, function_frontier
|
||||||
-- ** Abstract state information
|
-- ** Abstract state information
|
||||||
, absState
|
, CodeInfo(..)
|
||||||
, AbsStateMap
|
, addrAbsBlockState
|
||||||
|
, codeInfoMap
|
||||||
|
, unionCodeInfo
|
||||||
-- ** DiscoveryInfo utilities
|
-- ** DiscoveryInfo utilities
|
||||||
, getFunctionEntryPoint
|
, getFunctionEntryPoint
|
||||||
, inSameFunction
|
, inSameFunction
|
||||||
@ -57,18 +58,17 @@ import Data.Map.Strict (Map)
|
|||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Parameterized.Classes
|
import Data.Parameterized.Classes
|
||||||
import Data.Parameterized.Nonce
|
import Data.Parameterized.Nonce
|
||||||
import Data.Sequence (Seq)
|
|
||||||
import qualified Data.Sequence as Seq
|
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
|
import Data.Sequence (Seq)
|
||||||
|
import qualified Data.Sequence as Seq
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import Numeric (showHex)
|
import Numeric (showHex)
|
||||||
|
|
||||||
import Data.Macaw.AbsDomain.AbsState
|
import Data.Macaw.AbsDomain.AbsState
|
||||||
import Data.Macaw.Architecture.Info
|
import Data.Macaw.Architecture.Info
|
||||||
import Data.Macaw.Architecture.Syscall
|
|
||||||
import Data.Macaw.CFG
|
import Data.Macaw.CFG
|
||||||
import Data.Macaw.Memory
|
import Data.Macaw.Memory
|
||||||
import qualified Data.Macaw.Memory.Permissions as Perm
|
import qualified Data.Macaw.Memory.Permissions as Perm
|
||||||
@ -77,8 +77,29 @@ import Data.Macaw.Types
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- AbsStateMap
|
-- AbsStateMap
|
||||||
|
|
||||||
|
-- | All information specifc about a discovered code address.
|
||||||
|
data CodeInfo arch = CodeInfo
|
||||||
|
{ _addrAbsBlockState :: !(AbsBlockState (ArchReg arch))
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | The abstract state at the beginning of the code block.
|
||||||
|
addrAbsBlockState :: Simple Lens (CodeInfo arch) (AbsBlockState (ArchReg arch))
|
||||||
|
addrAbsBlockState = lens _addrAbsBlockState (\s v -> s { _addrAbsBlockState = v })
|
||||||
|
|
||||||
|
-- | 'joinCodeInfo x y' returns 'Nothing' if all states represented by 'y' are
|
||||||
|
-- also in 'x', and 'Just z' where 'z' represents an overapproximation
|
||||||
|
-- of the union of the states 'x' and 'y'.
|
||||||
|
unionCodeInfo :: RegisterInfo (ArchReg arch)
|
||||||
|
=> CodeInfo arch
|
||||||
|
-> CodeInfo arch
|
||||||
|
-> Maybe (CodeInfo arch)
|
||||||
|
unionCodeInfo x y =
|
||||||
|
case joinD (x^.addrAbsBlockState) (y^.addrAbsBlockState) of
|
||||||
|
Just z -> Just CodeInfo { _addrAbsBlockState = z }
|
||||||
|
Nothing -> Nothing
|
||||||
|
|
||||||
-- | Maps each code address to a set of abstract states
|
-- | Maps each code address to a set of abstract states
|
||||||
type AbsStateMap arch = Map (ArchSegmentedAddr arch) (AbsBlockState (ArchReg arch))
|
--type AbsStateMap arch = Map (ArchSegmentedAddr arch) (CodeInfo arch))
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- BlockRegion
|
-- BlockRegion
|
||||||
@ -187,8 +208,6 @@ data DiscoveryInfo arch ids
|
|||||||
-- ^ The initial memory when disassembly started.
|
-- ^ The initial memory when disassembly started.
|
||||||
, symbolNames :: !(Map (ArchSegmentedAddr arch) BS.ByteString)
|
, symbolNames :: !(Map (ArchSegmentedAddr arch) BS.ByteString)
|
||||||
-- ^ The set of symbol names (not necessarily complete)
|
-- ^ The set of symbol names (not necessarily complete)
|
||||||
, syscallPersonality :: !(SyscallPersonality arch)
|
|
||||||
-- ^ Syscall personality, mainly used by classifyBlock etc.
|
|
||||||
, archInfo :: !(ArchitectureInfo arch)
|
, archInfo :: !(ArchitectureInfo arch)
|
||||||
-- ^ Architecture-specific information needed for discovery.
|
-- ^ Architecture-specific information needed for discovery.
|
||||||
, _blocks :: !(Map (ArchSegmentedAddr arch) (BlockRegion arch ids))
|
, _blocks :: !(Map (ArchSegmentedAddr arch) (BlockRegion arch ids))
|
||||||
@ -205,14 +224,14 @@ data DiscoveryInfo arch ids
|
|||||||
-- inferred about it.
|
-- inferred about it.
|
||||||
, _frontier :: !(Map (ArchSegmentedAddr arch)
|
, _frontier :: !(Map (ArchSegmentedAddr arch)
|
||||||
(CodeAddrReason (ArchAddrWidth arch)))
|
(CodeAddrReason (ArchAddrWidth arch)))
|
||||||
-- ^ Set of addresses to explore next.
|
-- ^ Addresses to explore next.
|
||||||
--
|
--
|
||||||
-- This is a map so that we can associate a reason why a code address
|
-- This is a map so that we can associate a reason why a code
|
||||||
-- was added to the frontier.
|
-- address was added to the frontier.
|
||||||
, _function_frontier :: !(Map (ArchSegmentedAddr arch)
|
, _function_frontier :: !(Map (ArchSegmentedAddr arch)
|
||||||
(CodeAddrReason (ArchAddrWidth arch)))
|
(CodeAddrReason (ArchAddrWidth arch)))
|
||||||
-- ^ Set of functions to explore next.
|
-- ^ Set of functions to explore next.
|
||||||
, _absState :: !(AbsStateMap arch)
|
, _codeInfoMap :: !(Map (ArchSegmentedAddr arch) (CodeInfo arch))
|
||||||
-- ^ Map from code addresses to the abstract state at the start of
|
-- ^ Map from code addresses to the abstract state at the start of
|
||||||
-- the block.
|
-- the block.
|
||||||
}
|
}
|
||||||
@ -221,15 +240,13 @@ data DiscoveryInfo arch ids
|
|||||||
emptyDiscoveryInfo :: NonceGenerator (ST ids) ids
|
emptyDiscoveryInfo :: NonceGenerator (ST ids) ids
|
||||||
-> Memory (ArchAddrWidth arch)
|
-> Memory (ArchAddrWidth arch)
|
||||||
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
-> Map (ArchSegmentedAddr arch) BS.ByteString
|
||||||
-> SyscallPersonality arch
|
|
||||||
-> ArchitectureInfo arch
|
-> ArchitectureInfo arch
|
||||||
-- ^ Stack delta
|
-- ^ architecture/OS specific information
|
||||||
-> DiscoveryInfo arch ids
|
-> DiscoveryInfo arch ids
|
||||||
emptyDiscoveryInfo ng mem symbols sysp info = DiscoveryInfo
|
emptyDiscoveryInfo ng mem symbols info = DiscoveryInfo
|
||||||
{ nonceGen = ng
|
{ nonceGen = ng
|
||||||
, memory = mem
|
, memory = mem
|
||||||
, symbolNames = symbols
|
, symbolNames = symbols
|
||||||
, syscallPersonality = sysp
|
|
||||||
, archInfo = info
|
, archInfo = info
|
||||||
, _blocks = Map.empty
|
, _blocks = Map.empty
|
||||||
, _functionEntries = Set.empty
|
, _functionEntries = Set.empty
|
||||||
@ -237,7 +254,7 @@ emptyDiscoveryInfo ng mem symbols sysp info = DiscoveryInfo
|
|||||||
, _globalDataMap = Map.empty
|
, _globalDataMap = Map.empty
|
||||||
, _frontier = Map.empty
|
, _frontier = Map.empty
|
||||||
, _function_frontier = Map.empty
|
, _function_frontier = Map.empty
|
||||||
, _absState = Map.empty
|
, _codeInfoMap = Map.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks :: Simple Lens (DiscoveryInfo arch ids)
|
blocks :: Simple Lens (DiscoveryInfo arch ids)
|
||||||
@ -272,8 +289,9 @@ function_frontier :: Simple Lens (DiscoveryInfo arch ids)
|
|||||||
(CodeAddrReason (ArchAddrWidth arch)))
|
(CodeAddrReason (ArchAddrWidth arch)))
|
||||||
function_frontier = lens _function_frontier (\s v -> s { _function_frontier = v })
|
function_frontier = lens _function_frontier (\s v -> s { _function_frontier = v })
|
||||||
|
|
||||||
absState :: Simple Lens (DiscoveryInfo arch ids) (AbsStateMap arch)
|
codeInfoMap :: Simple Lens (DiscoveryInfo arch ids)
|
||||||
absState = lens _absState (\s v -> s { _absState = v })
|
(Map (ArchSegmentedAddr arch) (CodeInfo arch))
|
||||||
|
codeInfoMap = lens _codeInfoMap (\s v -> s { _codeInfoMap = v })
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
-- DiscoveryInfo utilities
|
-- DiscoveryInfo utilities
|
||||||
@ -440,8 +458,8 @@ tryGetStaticSyscallNo interp_state block_addr proc_state
|
|||||||
| BVValue _ call_no <- proc_state^.boundValue syscall_num_reg =
|
| BVValue _ call_no <- proc_state^.boundValue syscall_num_reg =
|
||||||
Just call_no
|
Just call_no
|
||||||
| Initial r <- proc_state^.boundValue syscall_num_reg
|
| Initial r <- proc_state^.boundValue syscall_num_reg
|
||||||
, Just absSt <- Map.lookup block_addr (interp_state ^. absState) =
|
, Just absSt <- interp_state^.codeInfoMap^.at block_addr =
|
||||||
asConcreteSingleton (absSt ^. absRegState ^. boundValue r)
|
asConcreteSingleton (absSt^.addrAbsBlockState^.absRegState^.boundValue r)
|
||||||
| otherwise =
|
| otherwise =
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
|
152
src/Data/Macaw/Discovery/JumpBounds.hs
Normal file
152
src/Data/Macaw/Discovery/JumpBounds.hs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
{-# LANGUAGE ExistentialQuantification #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
module Data.Macaw.Discovery.JumpBounds
|
||||||
|
( InitialIndexBounds
|
||||||
|
, arbitraryInitialBounds
|
||||||
|
, joinInitialBounds
|
||||||
|
, IndexBounds
|
||||||
|
, mkIndexBounds
|
||||||
|
, addUpperBounds
|
||||||
|
, lookupUpperBound
|
||||||
|
, nextBlockBounds
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Lens
|
||||||
|
import Control.Monad.State
|
||||||
|
import Data.Functor
|
||||||
|
import Data.Parameterized.Map (MapF)
|
||||||
|
import qualified Data.Parameterized.Map as MapF
|
||||||
|
import Data.Parameterized.NatRepr (maxUnsigned)
|
||||||
|
|
||||||
|
import Data.Macaw.CFG
|
||||||
|
import Data.Macaw.Types
|
||||||
|
|
||||||
|
-- | An upper bound on a value.
|
||||||
|
data UpperBounds tp = forall w . (tp ~ BVType w) => IntegerUpperBound Integer
|
||||||
|
|
||||||
|
instance Eq (UpperBounds tp) where
|
||||||
|
IntegerUpperBound x == IntegerUpperBound y = x == y
|
||||||
|
|
||||||
|
instance MapF.EqF UpperBounds where
|
||||||
|
eqF = (==)
|
||||||
|
|
||||||
|
instance Ord (UpperBounds tp) where
|
||||||
|
compare (IntegerUpperBound x) (IntegerUpperBound y) = compare x y
|
||||||
|
|
||||||
|
-- | Bounds for a function as the start of a block.
|
||||||
|
data InitialIndexBounds r
|
||||||
|
= InitialIndexBounds { initialRegUpperBounds :: !(MapF r UpperBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
instance MapF.TestEquality r => Eq (InitialIndexBounds r) where
|
||||||
|
x == y = initialRegUpperBounds x == initialRegUpperBounds y
|
||||||
|
|
||||||
|
-- | Create initial index bounds that can represent any system state.
|
||||||
|
arbitraryInitialBounds :: InitialIndexBounds reg
|
||||||
|
arbitraryInitialBounds = InitialIndexBounds { initialRegUpperBounds = MapF.empty }
|
||||||
|
|
||||||
|
|
||||||
|
type Changed = State Bool
|
||||||
|
|
||||||
|
markChanged :: Bool -> Changed ()
|
||||||
|
markChanged b = modify (|| b)
|
||||||
|
|
||||||
|
runChanged :: Changed a -> Maybe a
|
||||||
|
runChanged action =
|
||||||
|
case runState action False of
|
||||||
|
(r, True) -> Just r
|
||||||
|
(_, False) -> Nothing
|
||||||
|
|
||||||
|
-- | Take the union of two index bounds
|
||||||
|
joinInitialBounds :: forall r
|
||||||
|
. MapF.OrdF r
|
||||||
|
=> InitialIndexBounds r
|
||||||
|
-> InitialIndexBounds r
|
||||||
|
-> Maybe (InitialIndexBounds r)
|
||||||
|
joinInitialBounds old new = runChanged $ do
|
||||||
|
let combineF :: r tp -> UpperBounds tp -> UpperBounds tp -> Changed (Maybe (UpperBounds tp))
|
||||||
|
combineF _ (IntegerUpperBound x) (IntegerUpperBound y) =
|
||||||
|
markChanged (x < y) $> Just (IntegerUpperBound (max x y))
|
||||||
|
|
||||||
|
-- Mark upper bounds exclusively in old set.
|
||||||
|
-- If we have any only-old bounds add mark value as changed.
|
||||||
|
oldF :: MapF r UpperBounds -> Changed (MapF r UpperBounds)
|
||||||
|
oldF m = markChanged (not (MapF.null m)) $> MapF.empty
|
||||||
|
|
||||||
|
-- How to upper bounds exclusively in new set.
|
||||||
|
-- Drop any only-new bounds.
|
||||||
|
newF :: MapF r UpperBounds -> Changed (MapF r UpperBounds)
|
||||||
|
newF _ = pure MapF.empty
|
||||||
|
|
||||||
|
z <- MapF.mergeWithKeyM combineF oldF newF (initialRegUpperBounds old) (initialRegUpperBounds new)
|
||||||
|
pure InitialIndexBounds { initialRegUpperBounds = z }
|
||||||
|
|
||||||
|
-- | Information about bounds for a particular value within a block.
|
||||||
|
data IndexBounds reg ids
|
||||||
|
= IndexBounds { _regBounds :: !(MapF reg UpperBounds)
|
||||||
|
, _assignUpperBounds :: !(MapF (AssignId ids) UpperBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Maps assignment ids to the associated upper bounds
|
||||||
|
regBounds :: Simple Lens (IndexBounds reg ids) (MapF reg UpperBounds)
|
||||||
|
regBounds = lens _regBounds (\s v -> s { _regBounds = v })
|
||||||
|
|
||||||
|
-- | Maps assignment ids to the associated upper bounds
|
||||||
|
assignUpperBounds :: Simple Lens (IndexBounds reg ids) (MapF (AssignId ids) UpperBounds)
|
||||||
|
assignUpperBounds = lens _assignUpperBounds (\s v -> s { _assignUpperBounds = v })
|
||||||
|
|
||||||
|
-- | Create index bounds from initial index bounds.
|
||||||
|
mkIndexBounds :: InitialIndexBounds reg -> IndexBounds reg ids
|
||||||
|
mkIndexBounds i = IndexBounds { _regBounds = initialRegUpperBounds i
|
||||||
|
, _assignUpperBounds = MapF.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
addUpperBounds :: ( MapF.OrdF (ArchReg arch)
|
||||||
|
, HasRepr (ArchReg arch) TypeRepr
|
||||||
|
)
|
||||||
|
=> BVValue arch ids w
|
||||||
|
-> Integer -- ^ Upper bound as an unsigned number
|
||||||
|
-> IndexBounds (ArchReg arch) ids
|
||||||
|
-> Either String (IndexBounds (ArchReg arch) ids)
|
||||||
|
addUpperBounds v u bnds
|
||||||
|
-- Do nothing if upper bounds equals or exceeds function
|
||||||
|
| u >= maxUnsigned (valueWidth v) = Right bnds
|
||||||
|
| u < 0 = error "addUpperBounds given negative value."
|
||||||
|
| otherwise =
|
||||||
|
case v of
|
||||||
|
BVValue _ c | c <= u -> Right bnds
|
||||||
|
| otherwise -> Left "Constant given upper bound that is statically less than given bounds"
|
||||||
|
RelocatableValue{} -> Left "Relocatable value does not have upper bounds."
|
||||||
|
AssignedValue a ->
|
||||||
|
Right $ bnds & assignUpperBounds %~ MapF.insertWith min (assignId a) (IntegerUpperBound u)
|
||||||
|
Initial r ->
|
||||||
|
Right $ bnds & regBounds %~ MapF.insertWith min r (IntegerUpperBound u)
|
||||||
|
|
||||||
|
lookupUpperBound :: ( MapF.OrdF (ArchReg arch)
|
||||||
|
, Show (ArchReg arch (BVType w))
|
||||||
|
)
|
||||||
|
=> BVValue arch ids w
|
||||||
|
-> IndexBounds (ArchReg arch) ids
|
||||||
|
-> Either String Integer
|
||||||
|
lookupUpperBound v bnds =
|
||||||
|
case v of
|
||||||
|
BVValue _ i -> Right i
|
||||||
|
RelocatableValue{} -> Left "Relocatable values do not have bounds."
|
||||||
|
AssignedValue a ->
|
||||||
|
case MapF.lookup (assignId a) (bnds^.assignUpperBounds) of
|
||||||
|
Just (IntegerUpperBound bnd) -> Right bnd
|
||||||
|
Nothing -> Left $ "Could not find upper bounds for " ++ show (assignId a) ++ "."
|
||||||
|
Initial r ->
|
||||||
|
case MapF.lookup r (bnds^.regBounds) of
|
||||||
|
Just (IntegerUpperBound bnd) -> Right bnd
|
||||||
|
Nothing -> Left $ "Could not find upper bounds for " ++ show r ++ "."
|
||||||
|
|
||||||
|
nextBlockBounds :: RegState r (Value arch ids)
|
||||||
|
-> IndexBounds (ArchReg arch) ids
|
||||||
|
-> InitialIndexBounds (ArchReg arch)
|
||||||
|
nextBlockBounds _regs _bnds =
|
||||||
|
let m = undefined
|
||||||
|
in InitialIndexBounds { initialRegUpperBounds = m
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user