{-# LANGUAGE CPP, FlexibleInstances, UnboxedTuples, MagicHash #-} {-# OPTIONS_GHC -fno-cse -fno-warn-orphans #-} module DebuggerMonad where import GHC hiding (resume) import Data.IORef import Control.Monad import Exception (ExceptionMonad(..)) import GhcMonad () import DynFlags import MonadUtils import GhcMonad () import ObjLink (lookupSymbol) import GHC.Ptr () import Linker import GHC.Exts import System.IO data DebugState = DebugState { mainFile :: Maybe String, breaks :: [(Int, Module, Int)], -- number, module, line port :: Maybe Int, debugOutput :: Handle, mb_stdout_ptr :: Maybe (Ptr ()), mb_stderr_ptr :: Maybe (Ptr ()) } initState :: DebugState initState = DebugState { mainFile = Nothing, breaks = [], port = Nothing, debugOutput = stdout, mb_stdout_ptr = Nothing, mb_stderr_ptr = Nothing } newtype DebuggerMonad a = DebuggerMonad {toGhc :: IORef DebugState -> Ghc a} getDebugState :: DebuggerMonad DebugState getDebugState = DebuggerMonad $ \r -> liftIO $ readIORef r setDebugState :: DebugState -> DebuggerMonad () setDebugState s = DebuggerMonad $ \r -> liftIO $ writeIORef r s modifyDebugState :: (DebugState -> DebugState) -> DebuggerMonad () modifyDebugState f = DebuggerMonad $ \r -> liftIO $ readIORef r >>= writeIORef r . f liftGhc :: Ghc a -> DebuggerMonad a liftGhc m = DebuggerMonad $ \_ -> m startDebugger :: DebuggerMonad a -> DebugState -> Ghc a startDebugger g state = do ref <- liftIO $ newIORef state; toGhc g ref instance MonadIO DebuggerMonad where liftIO = liftGhc . liftIO instance Monad DebuggerMonad where (DebuggerMonad m) >>= k = DebuggerMonad $ \s -> m s >>= \a -> toGhc (k a) s return a = DebuggerMonad $ \_ -> return a instance Functor DebuggerMonad where fmap = liftM instance HasDynFlags DebuggerMonad where getDynFlags = getSessionDynFlags instance GhcMonad DebuggerMonad where setSession s' = liftGhc $ setSession s' getSession = liftGhc $ getSession instance ExceptionMonad DebuggerMonad where gcatch m h = DebuggerMonad $ \r -> toGhc m r `gcatch` (\e -> toGhc (h e) r) gmask f = DebuggerMonad $ \s -> gmask $ \io_restore -> let g_restore (DebuggerMonad m) = DebuggerMonad $ \s' -> io_restore (m s') in toGhc (f g_restore) s initInterpBuffering :: DebuggerMonad () initInterpBuffering = do dflags <- GHC.getSessionDynFlags liftIO $ initDynLinker dflags mb_stdout <- liftIO $ ObjLink.lookupSymbol "base_GHCziIOziHandleziFD_stdout_closure" mb_stderr <- liftIO $ ObjLink.lookupSymbol "base_GHCziIOziHandleziFD_stderr_closure" modifyDebugState $ \st -> st{mb_stdout_ptr = mb_stdout, mb_stderr_ptr = mb_stderr} flushInterpBuffers :: DebuggerMonad () flushInterpBuffers = do st <- getDebugState let (Just stdout_ptr) = mb_stdout_ptr st let (Just stderr_ptr) = mb_stderr_ptr st h1 <- liftIO $ getHandle (stdout_ptr) h2 <- liftIO $ getHandle (stderr_ptr) liftIO $ hFlush h1 liftIO $ hFlush h2 turnOffBuffering :: DebuggerMonad () turnOffBuffering = do st <- getDebugState let (Just stdout_ptr) = mb_stdout_ptr st let (Just stderr_ptr) = mb_stderr_ptr st h1 <- liftIO $ getHandle (stdout_ptr) h2 <- liftIO $ getHandle (stderr_ptr) liftIO $ hSetBuffering h1 NoBuffering liftIO $ hSetBuffering h2 NoBuffering getHandle :: Ptr () -> IO Handle getHandle (Ptr addr) = do case addrToAny# addr of (# hval #) -> return (unsafeCoerce# hval)