diff options
| author | Roman Smrž <roman.smrz@seznam.cz> | 2022-10-13 22:13:29 +0200 | 
|---|---|---|
| committer | Roman Smrž <roman.smrz@seznam.cz> | 2022-10-18 23:47:39 +0200 | 
| commit | 958c0a17842612f667cba89fe6712a2197985aad (patch) | |
| tree | 71a579d47469e9c9f96c13f0fd9b4daff41b4a28 | |
| parent | 000209c13299f1c046dc60e3649c17e9520680de (diff) | |
GDB process type and separate start function
| -rw-r--r-- | erebos-tester.cabal | 1 | ||||
| -rw-r--r-- | src/GDB.hs | 66 | ||||
| -rw-r--r-- | src/Main.hs | 23 | ||||
| -rw-r--r-- | src/Process.hs | 12 | 
4 files changed, 70 insertions, 32 deletions
| diff --git a/erebos-tester.cabal b/erebos-tester.cabal index 4c16133..f7152f5 100644 --- a/erebos-tester.cabal +++ b/erebos-tester.cabal @@ -41,6 +41,7 @@ executable erebos-tester-core                         Test                         Util    other-extensions:    TemplateHaskell +                       OverloadedStrings    default-extensions:  ExistentialQuantification                         FlexibleContexts                         FlexibleInstances @@ -1,10 +1,16 @@ +{-# LANGUAGE OverloadedStrings #-} +  module GDB ( -    gdbCmd, gdbInit, +    GDB, gdbProcess, +    gdbStart,      addInferior,      gdbSession,  ) where +import Control.Concurrent +import Control.Concurrent.STM  import Control.Monad.IO.Class +import Control.Monad.Reader  import Data.Text qualified as T  import Data.Text.IO qualified as T @@ -15,29 +21,61 @@ import System.Process  import Output  import Process +data GDB = GDB +    { gdbProcess_ :: Process +    } + +gdbProcess :: GDB -> Process +gdbProcess = gdbProcess_ +  gdbCmd :: String  gdbCmd = "gdb --quiet --interpreter=mi3" -gdbInit :: MonadIO m => Process -> m () -gdbInit gdb = do -    send gdb $ T.pack "-gdb-set schedule-multiple on" -    send gdb $ T.pack "-gdb-set mi-async on" -    send gdb $ T.pack "-gdb-set print symbol-loading off" +gdbStart :: (MonadOutput m, MonadFail m) => m GDB +gdbStart = do +    (Just hin, Just hout, Just herr, handle) <- liftIO $ createProcess (shell gdbCmd) +        { std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe +        } +    pout <- liftIO $ newTVarIO [] + +    let process = Process +            { procName = ProcNameGDB +            , procHandle = handle +            , procStdin = hin +            , procOutput = pout +            , procKillWith = Nothing +            , procNode = undefined +            } +        gdb = GDB +            { gdbProcess_ = process +            } + +    out <- getOutput +    liftIO $ void $ forkIO $ flip runReaderT out $ +        lineReadingLoop process hout $ outProc OutputChildStdout process +    liftIO $ void $ forkIO $ flip runReaderT out $ +        lineReadingLoop process herr $ outProc OutputChildStderr process + +    send process "-gdb-set schedule-multiple on" +    send process "-gdb-set mi-async on" +    send process "-gdb-set print symbol-loading off" + +    return gdb -addInferior :: MonadIO m => Process -> Int -> Pid -> m () -addInferior gdb i pid = do -    send gdb $ T.pack $ "-add-inferior" -    send gdb $ T.pack $ "-target-attach --thread-group i" ++ show i ++ " " ++ show pid -    send gdb $ T.pack $ "-exec-continue --thread-group i" ++ show i +addInferior :: MonadIO m => GDB -> Int -> Pid -> m () +addInferior GDB { gdbProcess_ = process } i pid = do +    send process $ "-add-inferior" +    send process $ "-target-attach --thread-group i" <> T.pack (show i) <> " " <> T.pack (show pid) +    send process $ "-exec-continue --thread-group i" <> T.pack (show i) -gdbSession :: MonadOutput m => Process -> m () +gdbSession :: MonadOutput m => GDB -> m ()  gdbSession gdb = do -    outPrompt $ T.pack "gdb> " +    outPrompt "gdb> "      liftIO loop      outClearPrompt    where      loop = catchIOError (Just <$> T.getLine) (\e -> if isEOFError e then return Nothing else ioError e) >>= \case          Just line -> do -            send gdb (T.pack "-interpreter-exec console \"" `T.append` line `T.append` T.pack "\"") +            send (gdbProcess gdb) ("-interpreter-exec console \"" <> line <> "\"")              loop          Nothing -> return () diff --git a/src/Main.hs b/src/Main.hs index 38c4099..0330733 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -14,7 +14,6 @@ import Data.Maybe  import Data.Scientific  import Data.Text (Text)  import qualified Data.Text as T -import qualified Data.Text.IO as T  import Text.Read (readMaybe) @@ -23,8 +22,6 @@ import System.Directory  import System.Environment  import System.Exit  import System.FilePath -import System.IO -import System.IO.Error  import System.Posix.Process  import System.Posix.Signals  import System.Process @@ -61,7 +58,7 @@ data TestEnv = TestEnv      { teOutput :: Output      , teFailed :: TVar (Maybe Failed)      , teOptions :: Options -    , teGDB :: Maybe (MVar Process) +    , teGDB :: Maybe (MVar GDB)      }  data TestState = TestState @@ -153,8 +150,8 @@ initNetwork inner = do      useGDB <- asks $ optGDB . teOptions . fst      mgdb <- if useGDB          then do -            gdb <- spawnOn (Left net) ProcNameGDB Nothing gdbCmd -            gdbInit gdb +            gdb <- gdbStart +            liftIO $ modifyMVar_ (netProcesses net) $ return . (gdbProcess gdb:)              Just <$> liftIO (newMVar gdb)          else return Nothing @@ -226,20 +223,10 @@ spawnOn target pname killWith cmd = do              , procNode = either (const undefined) id target              } -    let readingLoop :: Handle -> (Text -> TestRun ()) -> TestRun () -        readingLoop h act = -            liftIO (tryIOError (T.hGetLine h)) >>= \case -                Left err -                    | isEOFError err -> return () -                    | otherwise -> outProc OutputChildFail process $ T.pack $ "IO error: " ++ show err -                Right line -> do -                    act line -                    readingLoop h act - -    forkTest $ readingLoop hout $ \line -> do +    forkTest $ lineReadingLoop process hout $ \line -> do          outProc OutputChildStdout process line          liftIO $ atomically $ modifyTVar pout (++[line]) -    forkTest $ readingLoop herr $ \line -> do +    forkTest $ lineReadingLoop process herr $ \line -> do          case pname of               ProcNameTcpdump -> return ()               _ -> outProc OutputChildStderr process line diff --git a/src/Process.hs b/src/Process.hs index 153eb2b..de834a5 100644 --- a/src/Process.hs +++ b/src/Process.hs @@ -4,6 +4,7 @@ module Process (      textProcName, unpackProcName,      send,      outProc, +    lineReadingLoop,      closeProcess,  ) where @@ -18,6 +19,7 @@ import qualified Data.Text.IO as T  import System.Exit  import System.IO +import System.IO.Error  import System.Posix.Signals  import System.Process @@ -68,6 +70,16 @@ send p line = liftIO $ do  outProc :: MonadOutput m => OutputType -> Process -> Text -> m ()  outProc otype p line = outLine otype (textProcName $ procName p) line +lineReadingLoop :: MonadOutput m => Process -> Handle -> (Text -> m ()) -> m () +lineReadingLoop process h act = +    liftIO (tryIOError (T.hGetLine h)) >>= \case +        Left err +            | isEOFError err -> return () +            | otherwise -> outProc OutputChildFail process $ T.pack $ "IO error: " ++ show err +        Right line -> do +            act line +            lineReadingLoop process h act +  closeProcess :: (MonadIO m, MonadOutput m, MonadError Failed m) => Process -> m ()  closeProcess p = do      liftIO $ hClose $ procStdin p |