1 {-# LANGUAGE MagicHash, UnboxedTuples, CPP, ForeignFunctionInterface, GHCForeignImportPrim, UnliftedFFITypes, BangPatterns, RecordWildCards #-}
3 module GHC.HeapView where
5 import System.IO.Unsafe
8 import System.Environment
9 import GHC.Arr ((!), Array(..), elems)
11 import GHC.Constants ( wORD_SIZE, tAG_MASK, wORD_SIZE_IN_BITS )
14 import System.Mem.StableName
18 import Foreign.Storable
19 import Foreign.Marshal.Array
20 import Numeric ( showHex )
26 newtype HValue = HValue Any
28 -- A Safegard of HValues
31 type HalfWord = Word32
33 instance Show Box where
34 -- From libraries/base/GHC/Ptr.lhs
35 showsPrec _ (Box (HValue any)) rs =
36 -- unsafePerformIO (print "↓" >> pClosure any) `seq`
37 pad_out (showHex addr "") ++ (if tag>0 then "/" ++ show tag else "") ++ rs
39 ptr = W# (aToWord# any)
40 tag = ptr .&. fromIntegral tAG_MASK -- ((1 `shiftL` TAG_BITS) -1)
42 -- want 0s prefixed to pad it out to a fixed length.
44 '0':'x':(replicate (2*wORD_SIZE - length ls) '0') ++ ls
47 asBox x = Box (unsafeCoerce# x)
50 - StgInfoTable parsing derived from ByteCodeItbls.lhs
51 - Removed the code parameter for now
52 - Replaced Type by an enumeration
53 - Remove stuff dependent on GHCI_TABLES_NEXT_TO_CODE
57 data StgInfoTable = StgInfoTable {
65 instance Storable StgInfoTable where
72 sizeOf (undefined :: HalfWord),
80 = error "Storable StgInfoTable is read-only"
83 = runState (castPtr a0)
93 tipe = toEnum (fromIntegral (tipe'::HalfWord)),
97 fieldSz :: (Storable a, Storable b) => (a -> b) -> a -> Int
98 fieldSz sel x = sizeOf (sel x)
100 load :: Storable a => PtrIO a
101 load = do addr <- advance
104 type PtrIO = State (Ptr Word8) IO
106 advance :: Storable a => PtrIO (Ptr a)
107 advance = State adv where
108 adv addr = case castPtr addr of { addrCast -> return
109 (addr `plusPtr` sizeOfPointee addrCast, addrCast) }
111 sizeOfPointee :: (Storable a) => Ptr a -> Int
112 sizeOfPointee addr = sizeOf (typeHack addr)
113 where typeHack = undefined :: Ptr a -> a
115 store :: Storable a => a -> PtrIO ()
116 store x = do addr <- advance
120 - Embedded StateT, also from ByteCodeItbls
123 newtype State s m a = State (s -> m (s, a))
125 instance Monad m => Monad (State s m) where
126 return a = State (\s -> return (s, a))
127 State m >>= k = State (\s -> m s >>= \(s', a) -> case k a of State n -> n s')
128 fail str = State (\_ -> fail str)
130 lift m = State (\s -> m >>= \a -> return (s, a))
132 runState :: (Monad m) => s -> State s m a -> m a
133 runState s (State m) = m s >>= return . snd
136 - Data Type representing Closures
149 | CONSTR_NOCAF_STATIC
188 | MUT_ARR_PTRS_FROZEN0
189 | MUT_ARR_PTRS_FROZEN
202 deriving (Show, Eq, Enum, Ord)
256 , mccPayload :: [Box]
257 -- Card table ignored
264 BlockingQueueClosure {
278 allPtrs (ConsClosure {..}) = ptrArgs
279 allPtrs (ThunkClosure {..}) = ptrArgs
280 allPtrs (SelectorClosure {..}) = [selectee]
281 allPtrs (IndClosure {..}) = [indirectee]
282 allPtrs (APClosure {..}) = fun:payload
283 allPtrs (PAPClosure {..}) = fun:payload
284 allPtrs (BCOClosure {..}) = [instrs,literals,bcoptrs]
285 allPtrs (ArrWordsClosure {..}) = []
286 allPtrs (MutArrClosure {..}) = mccPayload
287 allPtrs (FunClosure {..}) = ptrArgs
288 allPtrs (OtherClosure {..}) = hvalues
292 #ifdef PRIM_SUPPORTS_ANY
293 foreign import prim "aToWordzh" aToWord# :: Any -> Word#
294 foreign import prim "slurpClosurezh" slurpClosure# :: Any -> (# Addr#, ByteArray#, Array# b #)
296 -- Workd-around code until http://hackage.haskell.org/trac/ghc/ticket/5931 was
299 foreign import prim "aToWordzh" aToWord'# :: Addr# -> Word#
300 foreign import prim "slurpClosurezh" slurpClosure'# :: Addr# -> (# Addr#, ByteArray#, Array# b #)
302 -- This is a datatype that has the same layout as Ptr, so that by
303 -- unsafeCoerce'ing, we obtain the Addr of the wrapped value
306 addrOf# :: Any -> Addr#
307 addrOf# a = case Ptr' a of mb@(Ptr' _) -> case unsafeCoerce# mb :: Ptr () of Ptr addr -> addr
309 aToWord# :: Any -> Word#
310 aToWord# a = aToWord'# (addrOf# a)
311 slurpClosure# :: Any -> (# Addr#, ByteArray#, Array# b #)
312 slurpClosure# a = slurpClosure'# (addrOf# a)
316 -- getClosure x >>= print
318 getClosureRaw :: a -> IO (Ptr StgInfoTable, [Word], [Box])
320 case slurpClosure# (unsafeCoerce# x) of
321 (# iptr, dat, ptrs #) -> do
322 let nelems = (I# (sizeofByteArray# dat)) `div` wORD_SIZE
323 words = [W# (indexWordArray# dat i) | I# i <- [0.. fromIntegral nelems -1] ]
324 pelems = I# (sizeofArray# ptrs)
325 ptrList = amap' Box $ Array 0 (pelems - 1) pelems ptrs
326 ptrList `seq` words `seq` return (Ptr iptr, words, ptrList)
328 -- From compiler/ghci/RtClosureInspect.hs
329 amap' :: (t -> b) -> Array Int t -> [b]
330 amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]
331 where g (I# i#) = case indexArray# arr# i# of
336 -- #include "../includes/rts/storage/ClosureTypes.h"
338 getHValueClosureData :: Box -> IO Closure
339 getHValueClosureData b@(Box a) = getClosureData a
341 -- derived from vacuum-1.0.0.2/src/GHC/Vacuum/Internal.hs, which got it from
342 -- compiler/ghci/DebuggerUtils.hs
343 dataConInfoPtrToNames :: Ptr StgInfoTable -> IO String
344 dataConInfoPtrToNames ptr = do
345 conDescAddress <- getConDescAddress ptr
346 wl <- peekArray0 0 conDescAddress
347 return $ fmap (chr . fromIntegral) wl
349 getConDescAddress :: Ptr StgInfoTable -> IO (Ptr Word8)
350 getConDescAddress ptr
352 offsetToString <- peek (ptr `plusPtr` (negate wORD_SIZE))
353 return $ (ptr `plusPtr` stdInfoTableSizeB)
354 `plusPtr` (fromIntegral (offsetToString :: Word))
355 -- This is code for !ghciTablesNextToCode:
357 | otherwise = peek . intPtrToPtr
363 -- hmmmmmm. Is there any way to tell this?
364 opt_SccProfilingOn = False
366 stdInfoTableSizeW :: Int
367 -- The size of a standard info table varies with profiling/ticky etc,
368 -- so we can't get it from Constants
369 -- It must vary in sync with mkStdInfoTable
371 = size_fixed + size_prof
373 size_fixed = 2 -- layout, type
374 size_prof | opt_SccProfilingOn = 2
377 stdInfoTableSizeB :: Int
378 stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE
381 getClosureData :: a -> IO Closure
382 getClosureData x = do
383 (iptr, words, ptrs) <- getClosureRaw x
386 t | t >= CONSTR && t <= CONSTR_NOCAF_STATIC -> do
387 name <- dataConInfoPtrToNames iptr
388 return $ ConsClosure itbl ptrs (drop (length ptrs + 1) words) name
390 t | t >= THUNK && t <= THUNK_STATIC -> do
391 return $ ThunkClosure itbl ptrs (drop (length ptrs + 2) words)
393 t | t >= FUN && t <= FUN_STATIC -> do
394 return $ FunClosure itbl ptrs (drop (length ptrs + 1) words)
397 return $ APClosure itbl
398 (fromIntegral $ words !! 2)
399 (fromIntegral $ shiftR (words !! 2) (wORD_SIZE_IN_BITS `div` 2))
400 (head ptrs) (tail ptrs)
403 return $ PAPClosure itbl
404 (fromIntegral $ words !! 2)
405 (fromIntegral $ shiftR (words !! 2) (wORD_SIZE_IN_BITS `div` 2))
406 (head ptrs) (tail ptrs)
409 return $ SelectorClosure itbl (head ptrs)
412 return $ IndClosure itbl (head ptrs)
414 return $ IndClosure itbl (head ptrs)
416 return $ IndClosure itbl (head ptrs)
419 return $ BCOClosure itbl (ptrs !! 0) (ptrs !! 1) (ptrs !! 2)
420 (fromIntegral $ words !! 4)
421 (fromIntegral $ shiftR (words !! 4) (wORD_SIZE_IN_BITS `div` 2))
425 return $ ArrWordsClosure itbl (words !! 1) (drop 2 words)
426 MUT_ARR_PTRS_FROZEN ->
427 return $ MutArrClosure itbl (words !! 2) (words !! 3) ptrs
430 return $ OtherClosure itbl ptrs words
431 -- return $ BlockingQueueClosure itbl
432 -- (ptrs !! 0) (ptrs !! 1) (ptrs !! 2) (ptrs !! 3)
434 -- return $ OtherClosure itbl ptrs words
435 x -> error $ "getClosureData: Cannot handle closure type " ++ show x