Add JumpTable bounds; remove code discovery dependency on syscall.

This commit is contained in:
Joe Hendrix 2017-01-28 12:57:49 -08:00
parent 3014a23a70
commit e962608f2c
No known key found for this signature in database
GPG Key ID: 00F67DE32381DB9F
8 changed files with 366 additions and 127 deletions

View File

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

View File

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

View File

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

View File

@ -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)]
} }

View File

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

View File

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

View File

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

View 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
}