Introduce ParsedBranch constructor.

This commit is contained in:
Joe Hendrix 2019-04-29 10:49:00 -07:00
parent 3331a19571
commit 8aa4650683
No known key found for this signature in database
GPG Key ID: 8DFA5FF784098C4F
6 changed files with 105 additions and 44 deletions

View File

@ -1088,7 +1088,7 @@ setAbsIP :: RegisterInfo r
-> AbsBlockState r
setAbsIP a b
-- Check to avoid reassigning next IP if it is not needed.
| CodePointers s False <- b^.absRegState^.curIP
| CodePointers s False <- b^.absRegState^.boundValue ip_reg
, Set.size s == 1
, Set.member a s =
b
@ -1316,12 +1316,12 @@ finalAbsBlockState :: forall a ids
-> RegState (ArchReg a) (Value a ids)
-- ^ Final values for abstract processor state
-> AbsBlockState (ArchReg a)
finalAbsBlockState c s =
finalAbsBlockState c regs =
let transferReg :: ArchReg a tp -> ArchAbsValue a tp
transferReg r = transferValue c (s^.boundValue r)
transferReg r = transferValue c (regs^.boundValue r)
in AbsBlockState { _absRegState = mkRegState transferReg
, _startAbsStack = c^.curAbsStack
, _initIndexBounds = Jmp.nextBlockBounds (c^.indexBounds) s
, _initIndexBounds = Jmp.nextBlockBounds (c^.indexBounds) regs
}
------------------------------------------------------------------------

View File

@ -242,7 +242,7 @@ data FunctionArgsState arch ids = FAS
_blockTransfer :: !(Map (ArchLabel arch) (ResultDemandsMap (ArchReg arch)))
-- | If a demand d is demanded of block lbl then the block demands S, s.t.
-- blockDemandMap ^. at lbl ^. at d = Just S
-- `blockDemandMap ^. at lbl ^. at d = Just S1
, _blockDemandMap :: !(Map (ArchLabel arch) (DemandMap (ArchReg arch)))
-- | Maps each global block label to the set of blocks that have intra-procedural
@ -352,15 +352,21 @@ addBlockDemands lbl m =
blockDemandMap %= Map.insertWith demandMapUnion lbl m
-- Figure out the deps of the given registers and update the state for the current label
-- | Given a block and a maping from register to value after the block
-- has executed, this traverses the registers that will be available
-- in future blocks, and records a mapping from those registers to
-- their input dependencies.
recordBlockTransfer :: forall arch ids
. ( OrdF (ArchReg arch)
, FoldableFC (ArchFn arch)
)
=> ArchLabel arch
-- ^ Label for the current block.
-> RegState (ArchReg arch) (Value arch ids)
-- ^ Map from registers to values.
-> [Some (ArchReg arch)]
-> FunctionArgsM arch ids () -- Map (Some N.RegisterName) RegDeps
-- ^ List of registers that subsequent blocks may depend on.
-> FunctionArgsM arch ids ()
recordBlockTransfer lbl s rs = do
let doReg :: Some (ArchReg arch)
-> State (AssignmentCache (ArchReg arch) ids)
@ -436,16 +442,6 @@ calculateGlobalFixpoint s = go (s^.alwaysDemandMap) (s^.alwaysDemandMap)
let ds' = ds1 `demandSetDifference` ds2 in
if ds' == mempty then Nothing else Just ds'
transferDemands :: OrdF r
=> Map (Some r) (DemandSet r)
-> DemandSet r
-> DemandSet r
transferDemands xfer (DemandSet regs funs) =
-- Using ix here means we ignore any registers we don't know about,
-- e.g. caller-saved registers after a function call.
-- FIXME: is this the correct behavior?
mconcat (DemandSet mempty funs : [ xfer ^. ix r | r <- Set.toList regs ])
-- A function call is the only block type that results in the
-- generation of function call demands, so we split that aspect out
-- (callee saved are handled in summarizeBlock).
@ -575,6 +571,14 @@ summarizeBlock mem interpState addr stmts = do
recordBlockTransfer lbl procState archRegs
addIntraproceduralJumpTarget interpState lbl tgtAddr
ParsedBranch nextRegs cond trueAddr falseAddr -> do
demandValue lbl cond
-- record all propagations
let notIP (Some r) = isNothing (testEquality r ip_reg)
recordBlockTransfer lbl nextRegs (filter notIP archRegs)
addIntraproceduralJumpTarget interpState lbl trueAddr
addIntraproceduralJumpTarget interpState lbl falseAddr
ParsedLookupTable finalRegs lookup_idx vec -> do
demandValue lbl lookup_idx
-- record all propagations
@ -633,6 +637,17 @@ summarizeIter mem ist = do
summarizeBlock mem ist (pblockAddr reg) (blockStatementList reg)
summarizeIter mem ist
transferDemands :: OrdF r
=> Map (Some r) (DemandSet r)
-> DemandSet r
-> DemandSet r
transferDemands xfer (DemandSet regs funs) =
-- Using ix here means we ignore any registers we don't know about,
-- e.g. caller-saved registers after a function call.
-- FIXME: is this the correct behavior?
mconcat (DemandSet mempty funs : [ xfer ^. ix r | r <- Set.toList regs ])
calculateOnePred :: (OrdF (ArchReg arch))
=> DemandMap (ArchReg arch)
-> ArchLabel arch
@ -646,7 +661,6 @@ calculateOnePred newDemands predLbl = do
-- update uses, returning value before this iteration
seenDemands <- use (blockDemandMap . ix lbl')
addBlockDemands lbl' demands'
-- seenDemands <- blockDemandMap . ix lbl' <<%= demandMapUnion demands'
let diff :: OrdF r => DemandSet r -> DemandSet r -> Maybe (DemandSet r)

View File

@ -209,6 +209,8 @@ addStatementListDemands sl = do
traverseF_ addValueDemands regs
ParsedJump regs _ -> do
traverseF_ addValueDemands regs
ParsedBranch regs _ _ _ -> do
traverseF_ addValueDemands regs
ParsedLookupTable regs _idx _tbl -> do
traverseF_ addValueDemands regs
ParsedReturn regs -> do
@ -807,7 +809,7 @@ data ParseContext arch ids =
-- intra-procedural jumps to the entry points of new
-- functions.
, pctxFunAddr :: !(ArchSegmentOff arch)
-- ^ Address of function this block is being parsed as
-- ^ Address of function this block is being parsefd as
, pctxAddr :: !(ArchSegmentOff arch)
-- ^ Address of the current block
}
@ -900,6 +902,17 @@ removeUnassignedRegs initRegs finalRegs =
where initVal = initRegs^.boundValue r
in MapF.filterWithKey keepReg (regStateMap finalRegs)
-- | This returns true if the address may be the target of a
-- intra-procedural control flow transfer.
--
-- Specifically this checks if the address is executable and not the current
-- function address or a known function address.
allowedIntraTarget :: ParseContext arch ids -> ArchSegmentOff arch -> Bool
allowedIntraTarget ctx addr
= segmentFlags (segoffSegment addr) `Perm.hasPerm` Perm.execute
&& addr /= pctxFunAddr ctx
&& addr `Set.notMember` pctxKnownFnEntries ctx
-- | Return true if any value in structure contains the given
-- identifier.
containsAssignId :: forall t arch ids itp
@ -939,30 +952,53 @@ parseFetchAndExecute ctx idx initRegs stmts absProcState finalRegs = do
-- Try to figure out what control flow statement we have.
case () of
-- The block ends with a Mux, so we turn this into a `ParsedIte` statement.
_ | Just (Mux _ c t f) <- valueAsApp (finalRegs^.boundValue ip_reg) -> do
_ | Just (Mux _ c t f) <- valueAsApp (finalRegs^.boundValue ip_reg)
, Just trueTgtAddr <- valueAsSegmentOff mem t
-- Check that true branch is an allowed intra-procedural branch target
, allowedIntraTarget ctx trueTgtAddr
, Just falseTgtAddr <- valueAsSegmentOff mem f
-- Check that false branch is an allowed intra-procedural branch target
, allowedIntraTarget ctx falseTgtAddr -> do
mapM_ (recordWriteStmt ainfo mem absProcState') stmts
let l_regs = refineProcStateBounds c True $
refineProcState c absTrue absProcState'
let l_regs' = absEvalStmts ainfo l_regs stmts
let lState = finalRegs & boundValue ip_reg .~ t
(tStmts,trueIdx) <-
parseFetchAndExecute ctx (idx+1) initRegs Seq.empty l_regs' lState
-- Registers with true value set.
let trueRegs = finalRegs & boundValue ip_reg .~ t
-- Abstract state after true regs.
let trueEvalState =
let refinedTrueState = refineProcStateBounds c True $
refineProcState c absTrue absProcState'
in absEvalStmts ainfo refinedTrueState stmts
let trueAbsState = finalAbsBlockState trueEvalState trueRegs
let r_regs = refineProcStateBounds c False $
refineProcState c absFalse absProcState'
let r_regs' = absEvalStmts ainfo r_regs stmts
let rState = finalRegs & boundValue ip_reg .~ f
(fStmts,falseIdx) <-
parseFetchAndExecute ctx trueIdx initRegs Seq.empty r_regs' rState
-- Merge block state and add intra jump target.
let tStmts = StatementList { stmtsIdent = idx+1
, stmtsNonterm = []
, stmtsTerm = ParsedJump trueRegs trueTgtAddr
, stmtsAbsState = trueEvalState
}
let falseRegs = finalRegs & boundValue ip_reg .~ f
let falseEvalState =
let refinedFalseState = refineProcStateBounds c False $
refineProcState c absFalse absProcState'
in absEvalStmts ainfo refinedFalseState stmts
let falseAbsState = finalAbsBlockState falseEvalState falseRegs
intraJumpTargets %= ([(trueTgtAddr, trueAbsState), (falseTgtAddr, falseAbsState)]++)
let fStmts = StatementList { stmtsIdent = idx + 2
, stmtsNonterm = []
, stmtsTerm = ParsedJump falseRegs falseTgtAddr
, stmtsAbsState = falseEvalState
}
let ret = StatementList { stmtsIdent = idx
, stmtsNonterm = toList stmts
, stmtsTerm = ParsedIte c tStmts fStmts
, stmtsAbsState = absProcState'
}
pure (ret, falseIdx)
pure (ret, idx + 3)
-- Use architecture-specific callback to check if last statement was a call.
-- Note that in some cases the call is known not to return, and thus
@ -1007,16 +1043,8 @@ parseFetchAndExecute ctx idx initRegs stmts absProcState finalRegs = do
-- Jump to a block within this function.
| Just tgt_mseg <- valueAsSegmentOff mem (finalRegs^.boundValue ip_reg)
-- Check target block address is in executable segment.
, segmentFlags (segoffSegment tgt_mseg) `Perm.hasPerm` Perm.execute
-- Check the target address is not the entry point of this function.
-- N.B. These should instead decompile into calls or tail calls.
, tgt_mseg /= pctxFunAddr ctx
-- If we are trusting known function entries, then only mark as an
-- intra-procedural jump if the target is not a known function entry.
, not (tgt_mseg `Set.member` pctxKnownFnEntries ctx) -> do
-- Check that target is an allowed intra-procedural branch target.
, allowedIntraTarget ctx tgt_mseg -> do
mapM_ (recordWriteStmt ainfo mem absProcState') stmts
-- Merge block state and add intra jump target.
@ -1039,7 +1067,6 @@ parseFetchAndExecute ctx idx initRegs stmts absProcState finalRegs = do
abst = finalAbsBlockState absProcState' finalRegs
seq abst $ do
forM_ entries $ \tgtAddr -> do
let abst' = abst & setAbsIP tgtAddr
intraJumpTargets %= ((tgtAddr, abst'):)

View File

@ -162,6 +162,15 @@ data ParsedTermStmt arch ids
!(Relocation (ArchAddrWidth arch))
-- | A jump to an explicit address within a function.
| ParsedJump !(RegState (ArchReg arch) (Value arch ids)) !(ArchSegmentOff arch)
-- | @ParsedBranch regs cond trueAddr falseAddr@ represents a conditional
-- branch that jumps to `trueAddr` if `cond` is true and `falseAddr` otherwise.
--
-- The value assigned to the IP in `regs` should reflect this if-then-else
-- structure.
| ParsedBranch !(RegState (ArchReg arch) (Value arch ids))
!(Value arch ids BoolType)
!(ArchSegmentOff arch)
!(ArchSegmentOff arch)
-- | A lookup table that branches to one of a vector of addresses.
--
-- The registers store the registers, the value contains the index to jump
@ -212,6 +221,9 @@ ppTermStmt ppOff tstmt =
ParsedJump s addr ->
text "jump" <+> text (show addr) <$$>
indent 2 (pretty s)
ParsedBranch r c t f ->
text "branch" <+> pretty c <+> text (show t) <+> text (show f) <$$>
indent 2 (pretty r)
ParsedLookupTable s idx entries ->
text "ijump" <+> pretty idx <$$>
indent 2 (vcat (imap (\i v -> int i <+> text ":->" <+> text (show v))

View File

@ -361,6 +361,7 @@ termStmtToReturn sl = sl { M.stmtsTerm = tm }
tm0@M.ParsedReturn{} -> tm0
M.ParsedCall r _ -> M.ParsedReturn r
M.ParsedJump r _ -> M.ParsedReturn r
M.ParsedBranch r _ _ _ -> M.ParsedReturn r
M.ParsedLookupTable r _ _ -> M.ParsedReturn r
M.ParsedIte b l r -> M.ParsedIte b (termStmtToReturn l) (termStmtToReturn r)
M.ParsedArchTermStmt _ r _ -> M.ParsedReturn r
@ -379,6 +380,7 @@ termStmtToJump sl addr = sl { M.stmtsTerm = tm }
tm :: M.ParsedTermStmt arch ids
tm = case M.stmtsTerm sl of
M.ParsedJump r _ -> M.ParsedJump r addr
M.ParsedBranch r _ _ _ -> M.ParsedJump r addr
M.ParsedCall r _ -> M.ParsedJump r addr
M.ParsedReturn r -> M.ParsedJump r addr
M.ParsedLookupTable r _ _ -> M.ParsedJump r addr

View File

@ -1411,6 +1411,12 @@ addMacawParsedTermStmt blockLabelMap thisAddr tstmt = do
M.ParsedJump regs nextAddr -> do
setMachineRegs =<< createRegStruct regs
addTermStmt $ CR.Jump (parsedBlockLabel blockLabelMap nextAddr 0)
M.ParsedBranch regs c trueAddr falseAddr -> do
setMachineRegs =<< createRegStruct regs
crucCond <- valueToCrucible c
let tlbl = parsedBlockLabel blockLabelMap trueAddr 0
let flbl = parsedBlockLabel blockLabelMap falseAddr 0
addTermStmt $! CR.Br crucCond tlbl flbl
M.ParsedLookupTable regs idx possibleAddrs -> do
setMachineRegs =<< createRegStruct regs
addSwitch blockLabelMap idx possibleAddrs