-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathMonad.hs
266 lines (232 loc) · 9.52 KB
/
Monad.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
-----------------------------------------------------------------------
-- |
-- Module : Lang.Crucible.LLVM.Translation.Monad
-- Description : Translation monad for LLVM and support operations
-- Copyright : (c) Galois, Inc 2018
-- License : BSD3
-- Maintainer : Rob Dockins <[email protected]>
-- Stability : provisional
-----------------------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Lang.Crucible.LLVM.Translation.Monad
( -- * Generator monad
LLVMGenerator
, LLVMGenerator'
, LLVMState(..)
, identMap
, blockInfoMap
, translationWarnings
, functionSymbol
, addWarning
, LLVMTranslationWarning(..)
, IdentMap
, LLVMBlockInfo(..)
, LLVMBlockInfoMap
, buildBlockInfoMap
, initialState
, getMemVar
-- * Malformed modules
, MalformedLLVMModule(..)
, malformedLLVMModule
, renderMalformedLLVMModule
-- * LLVMContext
, LLVMContext(..)
, llvmTypeCtx
, mkLLVMContext
, useTypedVal
) where
import Control.Lens hiding (op, (:>), to, from )
import Control.Monad.State.Strict
import Data.IORef (IORef, modifyIORef)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import Data.Text (Text)
import qualified Text.LLVM.AST as L
import qualified Data.Parameterized.Context as Ctx
import Data.Parameterized.NatRepr as NatRepr
import Data.Parameterized.Some
import Lang.Crucible.CFG.Generator
import Lang.Crucible.Panic ( panic )
import Lang.Crucible.LLVM.DataLayout
import Lang.Crucible.LLVM.Extension
import Lang.Crucible.LLVM.MalformedLLVMModule
import Lang.Crucible.LLVM.MemModel
import Lang.Crucible.LLVM.MemType
import Lang.Crucible.LLVM.Translation.BlockInfo
import Lang.Crucible.LLVM.Translation.Types
import Lang.Crucible.LLVM.TypeContext
import Lang.Crucible.Types
------------------------------------------------------------------------
-- ** LLVMContext
-- | Information about the LLVM module.
data LLVMContext arch
= LLVMContext
{ -- | Map LLVM symbols to their associated state.
llvmArch :: ArchRepr arch
, llvmPtrWidth :: forall a. (16 <= (ArchWidth arch) => NatRepr (ArchWidth arch) -> a) -> a
, llvmMemVar :: GlobalVar Mem
, _llvmTypeCtx :: TypeContext
-- | For each global variable symbol, compute the set of
-- aliases to that symbol
, llvmGlobalAliases :: Map L.Symbol (Set L.GlobalAlias)
-- | For each function symbol, compute the set of
-- aliases to that symbol
, llvmFunctionAliases :: Map L.Symbol (Set L.GlobalAlias)
}
llvmTypeCtx :: Simple Lens (LLVMContext arch) TypeContext
llvmTypeCtx = lens _llvmTypeCtx (\s v -> s{ _llvmTypeCtx = v })
mkLLVMContext :: GlobalVar Mem
-> L.Module
-> IO (Some LLVMContext)
mkLLVMContext mvar m = do
let (errs, typeCtx) = typeContextFromModule m
unless (null errs) $
malformedLLVMModule "Failed to construct LLVM type context" errs
let dl = llvmDataLayout typeCtx
case mkNatRepr (ptrBitwidth dl) of
Some (wptr :: NatRepr wptr) | Just LeqProof <- testLeq (knownNat @16) wptr ->
withPtrWidth wptr $
do let archRepr = X86Repr wptr -- FIXME! we should select the architecture based on
-- the target triple, but llvm-pretty doesn't capture this
-- currently.
let ctx :: LLVMContext (X86 wptr)
ctx = LLVMContext
{ llvmArch = archRepr
, llvmMemVar = mvar
, llvmPtrWidth = \x -> x wptr
, _llvmTypeCtx = typeCtx
, llvmGlobalAliases = mempty -- these are computed later
, llvmFunctionAliases = mempty -- these are computed later
}
return (Some ctx)
_ ->
fail ("Cannot load LLVM bitcode file with illegal pointer width: " ++ show (dl^.ptrSize))
-- | A monad providing state and continuations for translating LLVM expressions
-- to CFGs.
type LLVMGenerator s arch ret a =
(?lc :: TypeContext, HasPtrWidth (ArchWidth arch)) =>
Generator LLVM s (LLVMState arch) ret IO a
-- | @LLVMGenerator@ without the constraint, can be nested further inside monads.
type LLVMGenerator' s arch ret =
Generator LLVM s (LLVMState arch) ret IO
-- LLVMState
getMemVar :: LLVMGenerator s arch reg (GlobalVar Mem)
getMemVar = llvmMemVar . llvmContext <$> get
-- | Maps identifiers to an associated register or defined expression.
type IdentMap s = Map L.Ident (Either (Some (Reg s)) (Some (Atom s)))
-- | A warning generated during translation
data LLVMTranslationWarning =
LLVMTranslationWarning
L.Symbol -- ^ Function name in which the warning was generated
Position -- ^ Source position where the warning was generated
Text -- ^ Description of the warning
data LLVMState arch s
= LLVMState
{ -- | Map from identifiers to associated register shape
_identMap :: !(IdentMap s)
, _blockInfoMap :: !(LLVMBlockInfoMap s)
, llvmContext :: LLVMContext arch
, _translationWarnings :: IORef [LLVMTranslationWarning]
, _functionSymbol :: L.Symbol
}
identMap :: Lens' (LLVMState arch s) (IdentMap s)
identMap = lens _identMap (\s v -> s { _identMap = v })
blockInfoMap :: Lens' (LLVMState arch s) (LLVMBlockInfoMap s)
blockInfoMap = lens _blockInfoMap (\s v -> s { _blockInfoMap = v })
translationWarnings :: Lens' (LLVMState arch s) (IORef [LLVMTranslationWarning])
translationWarnings = lens _translationWarnings (\s v -> s { _translationWarnings = v })
functionSymbol :: Lens' (LLVMState arch s) L.Symbol
functionSymbol = lens _functionSymbol (\s v -> s{ _functionSymbol = v })
addWarning :: Text -> LLVMGenerator s arch ret ()
addWarning warn =
do r <- use translationWarnings
s <- use functionSymbol
p <- getPosition
liftIO (modifyIORef r ((LLVMTranslationWarning s p warn):))
-- | Given a list of LLVM formal parameters and a corresponding crucible
-- register assignment, build an IdentMap mapping LLVM identifiers to
-- corresponding crucible registers.
buildIdentMap :: (?lc :: TypeContext, HasPtrWidth wptr)
=> [L.Typed L.Ident]
-> Bool -- ^ varargs
-> CtxRepr ctx
-> Ctx.Assignment (Atom s) ctx
-> IdentMap s
-> IdentMap s
buildIdentMap ts True ctx asgn m =
-- Vararg functions are translated as taking a vector of extra arguments
packBase (VectorRepr AnyRepr) ctx asgn $ \_x ctx' asgn' ->
buildIdentMap ts False ctx' asgn' m
buildIdentMap [] _ ctx _ m
| Ctx.null ctx = m
| otherwise =
panic "crucible-llvm:Translation.buildIdentMap"
[ "buildIdentMap: passed arguments do not match LLVM input signature" ]
buildIdentMap (ti:ts) _ ctx asgn m = do
let ty = case liftMemType (L.typedType ti) of
Right t -> t
Left err -> panic "crucible-llvm:Translation.buildIdentMap"
[ "Error attempting to lift type " <> show ti
, show err
]
packType ty ctx asgn $ \x ctx' asgn' ->
buildIdentMap ts False ctx' asgn' (Map.insert (L.typedValue ti) (Right x) m)
-- | Build the initial LLVM generator state upon entry to to the entry point of a function.
initialState :: (?lc :: TypeContext, HasPtrWidth wptr)
=> L.Define
-> LLVMContext arch
-> CtxRepr args
-> Ctx.Assignment (Atom s) args
-> IORef [LLVMTranslationWarning]
-> LLVMState arch s
initialState d llvmctx args asgn warnRef =
let m = buildIdentMap (reverse (L.defArgs d)) (L.defVarArgs d) args asgn Map.empty in
LLVMState { _identMap = m
, _blockInfoMap = Map.empty
, llvmContext = llvmctx
, _translationWarnings = warnRef
, _functionSymbol = L.defName d
}
-- | Given an LLVM type and a type context and a register assignment,
-- peel off the rightmost register from the assignment, which is
-- expected to match the given LLVM type. Pass the register and
-- the remaining type and register context to the given continuation.
--
-- This procedure is used to set up the initial state of the
-- registers at the entry point of a function.
packType :: HasPtrWidth wptr
=> MemType
-> CtxRepr ctx
-> Ctx.Assignment (Atom s) ctx
-> (forall ctx'. Some (Atom s) -> CtxRepr ctx' -> Ctx.Assignment (Atom s) ctx' -> a)
-> a
packType tp ctx asgn k =
llvmTypeAsRepr tp $ \repr ->
packBase repr ctx asgn k
packBase
:: TypeRepr tp
-> CtxRepr ctx
-> Ctx.Assignment (Atom s) ctx
-> (forall ctx'. Some (Atom s) -> CtxRepr ctx' -> Ctx.Assignment (Atom s) ctx' -> a)
-> a
packBase ctp ctx0 asgn k =
case ctx0 of
ctx' Ctx.:> ctp' ->
case testEquality ctp ctp' of
Nothing -> error $ unwords ["crucible type mismatch",show ctp,show ctp']
Just Refl ->
let asgn' = Ctx.init asgn
idx = Ctx.nextIndex (Ctx.size asgn')
in k (Some (asgn Ctx.! idx))
ctx'
asgn'
_ -> error "packType: ran out of actual arguments!"