{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wno-unused-imports #-}
module GHC.Debug.Client.Monad
( DebugMonad(..)
, run
, DebugM
, Debuggee
, traceWrite
, runTrace
, withDebuggeeRun
, withDebuggeeConnect
, debuggeeRun
, debuggeeConnect
, debuggeeClose
, snapshotInit
, snapshotRun
, outputRequestLog
) where
import Control.Exception (finally)
import Network.Socket
import System.Process
import System.Environment
import GHC.Debug.Client.Monad.Class
import GHC.Debug.Types (Request(..))
import qualified GHC.Debug.Client.Monad.Simple as S
import System.IO
type DebugM = S.DebugM
newtype Debuggee = Debuggee { Debuggee -> DebugEnv DebugM
debuggeeEnv :: DebugEnv DebugM }
runTrace :: Debuggee -> DebugM a -> IO a
runTrace :: forall a. Debuggee -> DebugM a -> IO a
runTrace (Debuggee DebugEnv DebugM
e) DebugM a
act = do
(a
r, [String]
ws) <- forall (m :: * -> *) a.
DebugMonad m =>
DebugEnv m -> m a -> IO (a, [String])
runDebugTrace DebugEnv DebugM
e DebugM a
act
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ String -> IO ()
putStrLn [String]
ws
return a
r
traceWrite :: DebugMonad m => Show a => a -> m ()
traceWrite :: forall (m :: * -> *) a. (DebugMonad m, Show a) => a -> m ()
traceWrite = forall (m :: * -> *). DebugMonad m => String -> m ()
traceMsg forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show
run :: Debuggee -> DebugM a -> IO a
run :: forall a. Debuggee -> DebugM a -> IO a
run (Debuggee DebugEnv DebugM
d) = forall (m :: * -> *) a. DebugMonad m => DebugEnv m -> m a -> IO a
runDebug DebugEnv DebugM
d
withDebuggeeRun :: FilePath
-> FilePath
-> (Debuggee -> IO a)
-> IO a
withDebuggeeRun :: forall a. String -> String -> (Debuggee -> IO a) -> IO a
withDebuggeeRun String
exeName String
socketName Debuggee -> IO a
action = do
CreateProcess
cp <- String -> String -> IO CreateProcess
debuggeeProcess String
exeName String
socketName
forall a.
CreateProcess
-> (Maybe Handle
-> Maybe Handle -> Maybe Handle -> ProcessHandle -> IO a)
-> IO a
withCreateProcess CreateProcess
cp forall a b. (a -> b) -> a -> b
$ \Maybe Handle
_ Maybe Handle
_ Maybe Handle
_ ProcessHandle
_ -> do
forall a. String -> (Debuggee -> IO a) -> IO a
withDebuggeeConnect String
socketName Debuggee -> IO a
action
withDebuggeeConnect :: FilePath
-> (Debuggee -> IO a)
-> IO a
withDebuggeeConnect :: forall a. String -> (Debuggee -> IO a) -> IO a
withDebuggeeConnect String
socketName Debuggee -> IO a
action = do
Debuggee
new_env <- String -> IO Debuggee
debuggeeConnect String
socketName
Debuggee -> IO a
action Debuggee
new_env
forall a b. IO a -> IO b -> IO a
`finally`
Debuggee -> IO ()
debuggeeClose Debuggee
new_env
debuggeeRun :: FilePath
-> FilePath
-> IO Debuggee
debuggeeRun :: String -> String -> IO Debuggee
debuggeeRun String
exeName String
socketName = do
(Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
_ <- CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> String -> IO CreateProcess
debuggeeProcess String
exeName String
socketName
String -> IO Debuggee
debuggeeConnect String
socketName
debuggeeConnect :: FilePath
-> IO Debuggee
debuggeeConnect :: String -> IO Debuggee
debuggeeConnect String
socketName = do
Socket
s <- Family -> SocketType -> ProtocolNumber -> IO Socket
socket Family
AF_UNIX SocketType
Stream ProtocolNumber
defaultProtocol
Socket -> SockAddr -> IO ()
connect Socket
s (String -> SockAddr
SockAddrUnix String
socketName)
Handle
hdl <- Socket -> IOMode -> IO Handle
socketToHandle Socket
s IOMode
ReadWriteMode
Debuggee
new_env <- forall (m :: * -> *). DebugMonad m => Mode -> IO (DebugEnv m)
newEnv @DebugM (Handle -> Mode
SocketMode Handle
hdl)
return (DebugEnv DebugM -> Debuggee
Debuggee Debuggee
new_env)
snapshotInit :: FilePath -> IO Debuggee
snapshotInit :: String -> IO Debuggee
snapshotInit String
fp = DebugEnv DebugM -> Debuggee
Debuggee forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). DebugMonad m => Mode -> IO (DebugEnv m)
newEnv @DebugM (String -> Mode
SnapshotMode String
fp)
snapshotRun :: FilePath -> (Debuggee -> IO a) -> IO a
snapshotRun :: forall a. String -> (Debuggee -> IO a) -> IO a
snapshotRun String
fp Debuggee -> IO a
k = do
Debuggee
denv <- String -> IO Debuggee
snapshotInit String
fp
Debuggee -> IO a
k Debuggee
denv
debuggeeClose :: Debuggee -> IO ()
debuggeeClose :: Debuggee -> IO ()
debuggeeClose Debuggee
d = forall a. Debuggee -> DebugM a -> IO a
run Debuggee
d forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) resp.
(DebugMonad m, Show resp, Typeable resp) =>
Request resp -> m resp
request Request ()
RequestResume
debuggeeProcess :: FilePath -> FilePath -> IO CreateProcess
debuggeeProcess :: String -> String -> IO CreateProcess
debuggeeProcess String
exe String
sockName = do
[(String, String)]
e <- IO [(String, String)]
getEnvironment
return $
(String -> [String] -> CreateProcess
proc String
exe []) { env :: Maybe [(String, String)]
env = forall a. a -> Maybe a
Just ((String
"GHC_DEBUG_SOCKET", String
sockName) forall a. a -> [a] -> [a]
: [(String, String)]
e) }
outputRequestLog :: Debuggee -> IO ()
outputRequestLog :: Debuggee -> IO ()
outputRequestLog = forall (m :: * -> *). DebugMonad m => DebugEnv m -> IO ()
printRequestLog @DebugM forall b c a. (b -> c) -> (a -> b) -> a -> c
. Debuggee -> DebugEnv DebugM
debuggeeEnv