1 {-# LANGUAGE CPP, ScopedTypeVariables, DoAndIfThenElse, NondecreasingIndentation, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
2 -- | A disassembler for ByteCode objects as used by GHCi.
3 module GHC.Disassembler (
8 import qualified Data.ByteString.Lazy as BS
9 import Data.ByteString.Lazy (ByteString)
10 import Data.ByteString.Lazy.Builder
11 import Data.ByteString.Lazy.Builder.Extras
12 import Data.Binary.Get
18 import Data.Foldable ( Foldable )
19 import Data.Traversable ( Traversable )
21 #include "ghcautoconf.h"
22 #include "rts/Bytecodes.h"
24 -- | Converts the first @n@ bytes of this list of Words to a ByteString.
25 toBytes :: Word -> [Word] -> ByteString
27 BS.take (fromIntegral n) .
30 map (wordHost . fromIntegral)
32 -- | Given a list of pointers, a list of literals and a ByteString containing
33 -- byte code instructions, disassembles them into a list of byte code instructions.
34 disassemble :: forall box. [box] -> [Word] -> ByteString -> [BCI box]
35 disassemble ptrs lits = runGet $ do
36 -- Ignore length tag. Needs to be skipped with GHC versions with
37 -- http://hackage.haskell.org/trac/ghc/ticket/7518 included
39 #if SIZEOF_VOID_P == 8
46 getLiteral :: Get Word
47 getLiteral = ((!!) lits) . fromIntegral <$> getWord16host
50 p <- fromIntegral <$> getWord16host
51 n <- fromIntegral <$> getWord16host
52 return $ take n (drop p lits)
58 getPtr = getAddr . fromIntegral <$> getWord16host
60 nextInst :: Get [BCI box]
63 if e then return [] else do
65 let large = 0 /= w .&. 0x8000
67 let getLarge = if large then getWordhost else fromIntegral `fmap` getWord16host
68 let getLargeInt = if large then getInthost else fromIntegral `fmap` getInt16host
70 i <- case w .&. 0xff of
73 return $ BCISTKCHECK (n + 1)
80 return $ BCIPUSH_LL o1 o2
85 return $ BCIPUSH_LLL o1 o2 o3
91 return $ BCIPUSH_ALTS p
94 return $ BCIPUSH_ALTS_P p
97 return $ BCIPUSH_ALTS_N p
100 return $ BCIPUSH_ALTS_F p
101 bci_PUSH_ALTS_D -> do
103 return $ BCIPUSH_ALTS_D p
104 bci_PUSH_ALTS_L -> do
106 return $ BCIPUSH_ALTS_L p
107 bci_PUSH_ALTS_V -> do
109 return $ BCIPUSH_ALTS_V p
111 ubx_lits <- getLiterals
112 return $ BCIPUSH_UBX ubx_lits
113 bci_PUSH_APPLY_N -> do
114 return BCIPUSH_APPLY_N
115 bci_PUSH_APPLY_F -> do
116 return BCIPUSH_APPLY_F
117 bci_PUSH_APPLY_D -> do
118 return BCIPUSH_APPLY_D
119 bci_PUSH_APPLY_L -> do
120 return BCIPUSH_APPLY_L
121 bci_PUSH_APPLY_V -> do
122 return BCIPUSH_APPLY_V
123 bci_PUSH_APPLY_P -> do
124 return BCIPUSH_APPLY_P
125 bci_PUSH_APPLY_PP -> do
126 return BCIPUSH_APPLY_PP
127 bci_PUSH_APPLY_PPP -> do
128 return BCIPUSH_APPLY_PPP
129 bci_PUSH_APPLY_PPPP -> do
130 return BCIPUSH_APPLY_PPPP
131 bci_PUSH_APPLY_PPPPP -> do
132 return BCIPUSH_APPLY_PPPPP
133 bci_PUSH_APPLY_PPPPPP -> do
134 return BCIPUSH_APPLY_PPPPPP
138 return $ BCISLIDE p n
141 return $ BCIALLOC_AP n
142 bci_ALLOC_AP_NOUPD -> do
144 return $ BCIALLOC_AP_NOUPD n
148 return $ BCIALLOC_PAP a n
156 return $ BCIMKPAP n s
167 return $ BCITESTLT_I d t
171 return $ BCITESTEQ_I d t
175 return $ BCITESTLT_W d t
179 return $ BCITESTEQ_W d t
183 return $ BCITESTLT_F d t
187 return $ BCITESTEQ_F d t
191 return $ BCITESTLT_D d t
195 return $ BCITESTEQ_D d t
199 return $ BCITESTLT_P d t
203 return $ BCITESTEQ_P d t
214 return $ BCISWIZZLE p n
236 x -> error $ "Unknown opcode " ++ show x
237 (i :) `fmap` nextInst
240 -- | The various byte code instructions that GHCi supports.
244 | BCIPUSH_LL Word16 Word16
245 | BCIPUSH_LLL Word16 Word16 Word16
264 | BCIPUSH_APPLY_PPPPP
265 | BCIPUSH_APPLY_PPPPPP
266 /* | BCIPUSH_APPLY_PPPPPPP */
267 | BCISLIDE Word16 Word16
269 | BCIALLOC_AP_NOUPD Word16
270 | BCIALLOC_PAP Word16 Word16
271 | BCIMKAP Word16 Word16
272 | BCIMKPAP Word16 Word16
274 | BCIPACK Word Word16
275 | BCITESTLT_I Int Int
276 | BCITESTEQ_I Int Int
277 | BCITESTLT_F Word Int
278 | BCITESTEQ_F Word Int
279 | BCITESTLT_D Word Int
280 | BCITESTEQ_D Word Int
281 | BCITESTLT_P Word16 Int
282 | BCITESTEQ_P Word16 Int
286 | BCISWIZZLE Word16 Int16
295 | BCIBRK_FUN -- ^ We do not parse this opcode's arguments
296 | BCITESTLT_W Word Int
297 | BCITESTEQ_W Word Int
298 deriving (Show, Functor, Traversable, Foldable)
300 getInthost :: Get Int
301 getInthost = fromIntegral <$> getWordhost
303 getInt16host :: Get Int16
304 getInt16host = fromIntegral <$> getWord16host