{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes#-}
{-# LANGUAGE GHCForeignImportPrim #-}
module GHC.Stack.CloneStack (
StackSnapshot(..),
StackEntry(..),
cloneMyStack,
cloneThreadStack,
decode
) where
import Control.Concurrent.MVar
import Data.Maybe (catMaybes)
import Foreign
import GHC.Conc.Sync
import GHC.Exts (Int (I#), RealWorld, StackSnapshot#, ThreadId#, Array#, sizeofArray#, indexArray#, State#, StablePtr#)
import GHC.IO (IO (..))
import GHC.Stack.CCS (InfoProv (..), InfoProvEnt, ipeProv, peekInfoProv)
import GHC.Stable
data StackSnapshot = StackSnapshot !StackSnapshot#
foreign import prim "stg_decodeStackzh" decodeStack# :: StackSnapshot# -> State# RealWorld -> (# State# RealWorld, Array# (Ptr InfoProvEnt) #)
foreign import prim "stg_cloneMyStackzh" cloneMyStack# :: State# RealWorld -> (# State# RealWorld, StackSnapshot# #)
foreign import prim "stg_sendCloneStackMessagezh" sendCloneStackMessage# :: ThreadId# -> StablePtr# PrimMVar -> State# RealWorld -> (# State# RealWorld, (# #) #)
cloneMyStack :: IO StackSnapshot
cloneMyStack :: IO StackSnapshot
cloneMyStack = (State# RealWorld -> (# State# RealWorld, StackSnapshot #))
-> IO StackSnapshot
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, StackSnapshot #))
-> IO StackSnapshot)
-> (State# RealWorld -> (# State# RealWorld, StackSnapshot #))
-> IO StackSnapshot
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s ->
case (State# RealWorld -> (# State# RealWorld, StackSnapshot# #)
cloneMyStack# State# RealWorld
s) of (# State# RealWorld
s1, StackSnapshot#
stack #) -> (# State# RealWorld
s1, StackSnapshot# -> StackSnapshot
StackSnapshot StackSnapshot#
stack #)
cloneThreadStack :: ThreadId -> IO StackSnapshot
cloneThreadStack :: ThreadId -> IO StackSnapshot
cloneThreadStack (ThreadId ThreadId#
tid#) = do
MVar StackSnapshot
resultVar <- forall a. IO (MVar a)
newEmptyMVar @StackSnapshot
boxedPtr :: StablePtr PrimMVar
boxedPtr@(StablePtr StablePtr# PrimMVar
ptr) <- MVar StackSnapshot -> IO (StablePtr PrimMVar)
forall a. MVar a -> IO (StablePtr PrimMVar)
newStablePtrPrimMVar MVar StackSnapshot
resultVar
(State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, () #)) -> IO ())
-> (State# RealWorld -> (# State# RealWorld, () #)) -> IO ()
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s -> case ThreadId#
-> StablePtr# PrimMVar
-> State# RealWorld
-> (# State# RealWorld, (# #) #)
sendCloneStackMessage# ThreadId#
tid# StablePtr# PrimMVar
ptr State# RealWorld
s of (# State# RealWorld
s', (# #) #) -> (# State# RealWorld
s', () #)
StablePtr PrimMVar -> IO ()
forall a. StablePtr a -> IO ()
freeStablePtr StablePtr PrimMVar
boxedPtr
MVar StackSnapshot -> IO StackSnapshot
forall a. MVar a -> IO a
takeMVar MVar StackSnapshot
resultVar
data StackEntry = StackEntry
{ StackEntry -> String
functionName :: String,
StackEntry -> String
moduleName :: String,
StackEntry -> String
srcLoc :: String,
StackEntry -> Word
closureType :: Word
}
deriving (Int -> StackEntry -> ShowS
[StackEntry] -> ShowS
StackEntry -> String
(Int -> StackEntry -> ShowS)
-> (StackEntry -> String)
-> ([StackEntry] -> ShowS)
-> Show StackEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StackEntry -> ShowS
showsPrec :: Int -> StackEntry -> ShowS
$cshow :: StackEntry -> String
show :: StackEntry -> String
$cshowList :: [StackEntry] -> ShowS
showList :: [StackEntry] -> ShowS
Show, StackEntry -> StackEntry -> Bool
(StackEntry -> StackEntry -> Bool)
-> (StackEntry -> StackEntry -> Bool) -> Eq StackEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StackEntry -> StackEntry -> Bool
== :: StackEntry -> StackEntry -> Bool
$c/= :: StackEntry -> StackEntry -> Bool
/= :: StackEntry -> StackEntry -> Bool
Eq)
decode :: StackSnapshot -> IO [StackEntry]
decode :: StackSnapshot -> IO [StackEntry]
decode StackSnapshot
stackSnapshot = do
[Ptr InfoProvEnt]
stackEntries <- StackSnapshot -> IO [Ptr InfoProvEnt]
getDecodedStackArray StackSnapshot
stackSnapshot
[Maybe StackEntry]
ipes <- (Ptr InfoProvEnt -> IO (Maybe StackEntry))
-> [Ptr InfoProvEnt] -> IO [Maybe StackEntry]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Ptr InfoProvEnt -> IO (Maybe StackEntry)
unmarshall [Ptr InfoProvEnt]
stackEntries
[StackEntry] -> IO [StackEntry]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([StackEntry] -> IO [StackEntry])
-> [StackEntry] -> IO [StackEntry]
forall a b. (a -> b) -> a -> b
$ [Maybe StackEntry] -> [StackEntry]
forall a. [Maybe a] -> [a]
catMaybes [Maybe StackEntry]
ipes
where
unmarshall :: Ptr InfoProvEnt -> IO (Maybe StackEntry)
unmarshall :: Ptr InfoProvEnt -> IO (Maybe StackEntry)
unmarshall Ptr InfoProvEnt
ipe = if Ptr InfoProvEnt
ipe Ptr InfoProvEnt -> Ptr InfoProvEnt -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr InfoProvEnt
forall a. Ptr a
nullPtr then
Maybe StackEntry -> IO (Maybe StackEntry)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe StackEntry
forall a. Maybe a
Nothing
else do
InfoProv
infoProv <- (Ptr InfoProv -> IO InfoProv
peekInfoProv (Ptr InfoProv -> IO InfoProv)
-> (Ptr InfoProvEnt -> Ptr InfoProv)
-> Ptr InfoProvEnt
-> IO InfoProv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr InfoProvEnt -> Ptr InfoProv
ipeProv) Ptr InfoProvEnt
ipe
Maybe StackEntry -> IO (Maybe StackEntry)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe StackEntry -> IO (Maybe StackEntry))
-> Maybe StackEntry -> IO (Maybe StackEntry)
forall a b. (a -> b) -> a -> b
$ StackEntry -> Maybe StackEntry
forall a. a -> Maybe a
Just (InfoProv -> StackEntry
toStackEntry InfoProv
infoProv)
toStackEntry :: InfoProv -> StackEntry
toStackEntry :: InfoProv -> StackEntry
toStackEntry InfoProv
infoProv =
StackEntry
{ functionName :: String
functionName = InfoProv -> String
ipLabel InfoProv
infoProv,
moduleName :: String
moduleName = InfoProv -> String
ipMod InfoProv
infoProv,
srcLoc :: String
srcLoc = InfoProv -> String
ipLoc InfoProv
infoProv,
closureType :: Word
closureType = String -> Word
forall a. Read a => String -> a
read (String -> Word) -> (InfoProv -> String) -> InfoProv -> Word
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InfoProv -> String
ipDesc (InfoProv -> Word) -> InfoProv -> Word
forall a b. (a -> b) -> a -> b
$ InfoProv
infoProv
}
getDecodedStackArray :: StackSnapshot -> IO [Ptr InfoProvEnt]
getDecodedStackArray :: StackSnapshot -> IO [Ptr InfoProvEnt]
getDecodedStackArray (StackSnapshot StackSnapshot#
s) =
(State# RealWorld -> (# State# RealWorld, [Ptr InfoProvEnt] #))
-> IO [Ptr InfoProvEnt]
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld -> (# State# RealWorld, [Ptr InfoProvEnt] #))
-> IO [Ptr InfoProvEnt])
-> (State# RealWorld -> (# State# RealWorld, [Ptr InfoProvEnt] #))
-> IO [Ptr InfoProvEnt]
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
s0 -> case StackSnapshot#
-> State# RealWorld
-> (# State# RealWorld, Array# (Ptr InfoProvEnt) #)
decodeStack# StackSnapshot#
s State# RealWorld
s0 of
(# State# RealWorld
s1, Array# (Ptr InfoProvEnt)
a #) -> (# State# RealWorld
s1, (Array# (Ptr InfoProvEnt) -> Int -> [Ptr InfoProvEnt]
go Array# (Ptr InfoProvEnt)
a ((Int# -> Int
I# (Array# (Ptr InfoProvEnt) -> Int#
forall a. Array# a -> Int#
sizeofArray# Array# (Ptr InfoProvEnt)
a)) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) #)
where
go :: Array# (Ptr InfoProvEnt) -> Int -> [Ptr InfoProvEnt]
go :: Array# (Ptr InfoProvEnt) -> Int -> [Ptr InfoProvEnt]
go Array# (Ptr InfoProvEnt)
stack Int
0 = [Array# (Ptr InfoProvEnt) -> Int -> Ptr InfoProvEnt
stackEntryAt Array# (Ptr InfoProvEnt)
stack Int
0]
go Array# (Ptr InfoProvEnt)
stack Int
i = (Array# (Ptr InfoProvEnt) -> Int -> Ptr InfoProvEnt
stackEntryAt Array# (Ptr InfoProvEnt)
stack Int
i) Ptr InfoProvEnt -> [Ptr InfoProvEnt] -> [Ptr InfoProvEnt]
forall a. a -> [a] -> [a]
: Array# (Ptr InfoProvEnt) -> Int -> [Ptr InfoProvEnt]
go Array# (Ptr InfoProvEnt)
stack (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
stackEntryAt :: Array# (Ptr InfoProvEnt) -> Int -> Ptr InfoProvEnt
stackEntryAt :: Array# (Ptr InfoProvEnt) -> Int -> Ptr InfoProvEnt
stackEntryAt Array# (Ptr InfoProvEnt)
stack (I# Int#
i) = case Array# (Ptr InfoProvEnt) -> Int# -> (# Ptr InfoProvEnt #)
forall a. Array# a -> Int# -> (# a #)
indexArray# Array# (Ptr InfoProvEnt)
stack Int#
i of
(# Ptr InfoProvEnt
se #) -> Ptr InfoProvEnt
se