11module GHC.Debug.Client
22 ( Debuggee
3+ , DebuggeeAction
4+ , applyDebuggeeAction
35 , withDebuggee
46 , withDebuggeeSocket
57 , pauseDebuggee
@@ -26,6 +28,7 @@ module GHC.Debug.Client
2628import Control.Concurrent
2729import Control.Exception
2830import Control.Monad
31+ import Control.Monad.State.Lazy
2932import GHC.Debug.Types
3033import GHC.Debug.Decode
3134import GHC.Debug.Decode.Stack
@@ -55,11 +58,17 @@ import System.Directory
5558import Text.Printf
5659
5760data Debuggee = Debuggee { debuggeeHdl :: Handle
58- , debuggeeInfoTblEnv :: MVar ( HM. HashMap InfoTablePtr RawInfoTable )
61+ , debuggeeInfoTblEnv :: HM. HashMap InfoTablePtr RawInfoTable
5962 , debuggeeDwarf :: Maybe Dwarf
6063 , debuggeeFilename :: FilePath
6164 }
6265
66+ type DebuggeeAction a = StateT Debuggee IO a
67+
68+
69+ applyDebuggeeAction :: Debuggee -> DebuggeeAction a -> IO a
70+ applyDebuggeeAction = flip evalStateT
71+
6372
6473debuggeeProcess :: FilePath -> FilePath -> IO CreateProcess
6574debuggeeProcess exe sockName = do
@@ -69,7 +78,7 @@ debuggeeProcess exe sockName = do
6978
7079-- | Open a debuggee, this will also read the DWARF information
7180withDebuggee :: FilePath -- ^ path to executable
72- -> ( Debuggee -> IO a )
81+ -> DebuggeeAction a
7382 -> IO a
7483withDebuggee exeName action = do
7584 let sockName = " /tmp/ghc-debug2"
@@ -86,33 +95,39 @@ withDebuggee exeName action = do
8695withDebuggeeSocket :: FilePath -- ^ executable name of the debuggee
8796 -> FilePath -- ^ debuggee's socket location
8897 -> Maybe Dwarf
89- -> ( Debuggee -> IO a )
98+ -> DebuggeeAction a
9099 -> IO a
91100withDebuggeeSocket exeName sockName mdwarf action = do
92101 s <- socket AF_UNIX Stream defaultProtocol
93102 connect s (SockAddrUnix sockName)
94103 hdl <- socketToHandle s ReadWriteMode
95- infoTableEnv <- newMVar mempty
96- action (Debuggee hdl infoTableEnv mdwarf exeName)
104+ evalStateT action (Debuggee hdl mempty mdwarf exeName)
97105
98106-- | Send a request to a 'Debuggee' paused with 'pauseDebuggee'.
99- request :: Debuggee -> Request resp -> IO resp
100- request d req = doRequest (debuggeeHdl d) req
107+ request :: Request resp -> DebuggeeAction resp
108+ request req = do
109+ hdl <- gets debuggeeHdl
110+ liftIO $ doRequest hdl req
101111
102- lookupInfoTable :: Debuggee -> RawClosure -> IO (RawInfoTable , RawClosure )
103- lookupInfoTable d rc = do
112+ lookupInfoTable :: RawClosure -> DebuggeeAction (RawInfoTable , RawClosure )
113+ lookupInfoTable rc = do
104114 let ptr = getInfoTblPtr rc
105- itblEnv <- readMVar ( debuggeeInfoTblEnv d)
115+ itblEnv <- gets debuggeeInfoTblEnv
106116 case HM. lookup ptr itblEnv of
107117 Nothing -> do
108- [itbl] <- request d (RequestInfoTables [ptr])
109- modifyMVar_ (debuggeeInfoTblEnv d) $ return . HM. insert ptr itbl
118+ [itbl] <- request (RequestInfoTables [ptr])
119+ infoTblEnv <- gets debuggeeInfoTblEnv
120+ modify' $ \ s -> s { debuggeeInfoTblEnv = HM. insert ptr itbl infoTblEnv }
110121 return (itbl, rc)
111122 Just itbl -> return (itbl, rc)
112123
113- pauseDebuggee :: Debuggee -> IO a -> IO a
114- pauseDebuggee d =
115- bracket_ (void $ request d RequestPause ) (void $ request d RequestResume )
124+ pauseDebuggee :: DebuggeeAction a -> DebuggeeAction a
125+ pauseDebuggee action = do
126+ -- TODO: replace poor-mans bracket_ with proper implementation for StateT
127+ request RequestPause
128+ rc <- action
129+ request RequestResume
130+ return rc
116131
117132getDwarfInfo :: FilePath -> IO Dwarf
118133getDwarfInfo fn = do
@@ -121,10 +136,12 @@ getDwarfInfo fn = do
121136-- print $ DwarfPretty.dwarf dwarf
122137 return dwarf
123138
124- lookupDwarf :: Debuggee -> InfoTablePtr -> Maybe ([FilePath ], Int , Int )
125- lookupDwarf d (InfoTablePtr w) = do
126- (Dwarf units) <- debuggeeDwarf d
127- asum (map (lookupDwarfUnit (fromBE64 w)) units)
139+ lookupDwarf :: InfoTablePtr -> DebuggeeAction (Maybe ([FilePath ], Int , Int ))
140+ lookupDwarf (InfoTablePtr w) = do
141+ mDwarf <- gets debuggeeDwarf
142+ case mDwarf of
143+ Nothing -> return Nothing
144+ Just (Dwarf units) -> return $ asum (map (lookupDwarfUnit (fromBE64 w)) units)
128145
129146lookupDwarfUnit :: Word64 -> Boxed CompilationUnit -> Maybe ([FilePath ], Int , Int )
130147lookupDwarfUnit w (Boxed _ cu) = do
@@ -158,63 +175,66 @@ lookupDwarfLine w Nothing (d, nd) = do
158175 else Nothing
159176lookupDwarfLine _ (Just r) _ = Just r
160177
161- showFileSnippet :: Debuggee -> ([FilePath ], Int , Int ) -> IO ()
162- showFileSnippet d (fps, l, c) = go fps
178+ showFileSnippet :: ([FilePath ], Int , Int ) -> DebuggeeAction ()
179+ showFileSnippet (fps, l, c) = do
180+ dbgFilename <- gets debuggeeFilename
181+ liftIO $ go dbgFilename fps
163182 where
164- go [] = putStrLn (" No files could be found: " ++ show fps)
165- go (fp: fps) = do
166- exists <- doesFileExist fp
183+ go :: FilePath -> [FilePath ] -> IO ()
184+ go _ [] = putStrLn (" No files could be found: " ++ show fps)
185+ go dbgFilename (fp: fps) = do
186+ exists <- liftIO $ doesFileExist $ fp
167187 -- get file modtime
168188 if not exists
169- then go fps
189+ then go dbgFilename fps
170190 else do
171- fp `warnIfNewer` (debuggeeFilename d)
191+ -- TODO: get the modtime of debuggee above
192+ fp `warnIfNewer` dbgFilename
172193 src <- zip [1 .. ] . lines <$> readFile fp
173194 let ctx = take 10 (drop (max (l - 5 ) 0 ) src)
174195 putStrLn (fp <> " :" <> show l <> " :" <> show c)
175196 mapM_ (\ (n, l) ->
176197 let sn = show n
177198 in putStrLn (sn <> replicate (5 - length sn) ' ' <> l)) ctx
178199
179- dereferenceClosure :: Debuggee -> ClosurePtr -> IO Closure
180- dereferenceClosure d c = head <$> dereferenceClosures d [c]
200+ dereferenceClosure :: ClosurePtr -> DebuggeeAction Closure
201+ dereferenceClosure c = head <$> dereferenceClosures [c]
181202
182- dereferenceClosures :: Debuggee -> [ClosurePtr ] -> IO [Closure ]
183- dereferenceClosures d cs = do
184- raw_cs <- request d (RequestClosures cs)
203+ dereferenceClosures :: [ClosurePtr ] -> DebuggeeAction [Closure ]
204+ dereferenceClosures cs = do
205+ raw_cs <- request (RequestClosures cs)
185206 let its = map getInfoTblPtr raw_cs
186207 -- print $ map (lookupDwarf d) its
187- raw_its <- request d (RequestInfoTables its)
208+ raw_its <- request (RequestInfoTables its)
188209 return $ map (uncurry decodeClosure) (zip raw_its (zip cs raw_cs))
189210
190- dereferenceStack :: Debuggee -> StackCont -> IO Stack
191- dereferenceStack d (StackCont stack) = do
192- print stack
193- i <- lookupInfoTable d (coerce stack)
211+ dereferenceStack :: StackCont -> DebuggeeAction Stack
212+ dereferenceStack (StackCont stack) = do
213+ liftIO $ print stack
214+ i <- lookupInfoTable (coerce stack)
194215 let st_it = decodeInfoTable . fst $ i
195- print i
196- print st_it
197- bt <- request d (RequestBitmap (getInfoTblPtr (coerce stack)))
216+ liftIO $ print i
217+ liftIO $ print st_it
218+ bt <- request (RequestBitmap (getInfoTblPtr (coerce stack)))
198219 let decoded_stack = decodeStack stack st_it bt
199- print decoded_stack
220+ liftIO $ print decoded_stack
200221 return decoded_stack
201222
202- dereferenceConDesc :: Debuggee -> ClosurePtr -> IO ConstrDesc
203- dereferenceConDesc d i = do
204- request d (RequestConstrDesc i)
223+ dereferenceConDesc :: ClosurePtr -> DebuggeeAction ConstrDesc
224+ dereferenceConDesc i = request (RequestConstrDesc i)
205225
206226
207- fullTraversal :: Debuggee -> ClosurePtr -> IO UClosure
208- fullTraversal d c = do
209- dc <- dereferenceClosure d c
210- print dc
211- MkFix1 <$> tritraverse ( dereferenceConDesc d) ( fullStackTraversal d) ( fullTraversal d) dc
227+ fullTraversal :: ClosurePtr -> DebuggeeAction UClosure
228+ fullTraversal c = do
229+ dc <- dereferenceClosure c
230+ liftIO $ print dc
231+ MkFix1 <$> tritraverse dereferenceConDesc fullStackTraversal fullTraversal dc
212232
213- fullStackTraversal :: Debuggee -> StackCont -> IO UStack
214- fullStackTraversal d sc = do
215- ds <- dereferenceStack d sc
216- print ds
217- MkFix2 <$> traverse ( fullTraversal d) ds
233+ fullStackTraversal :: StackCont -> DebuggeeAction UStack
234+ fullStackTraversal sc = do
235+ ds <- dereferenceStack sc
236+ liftIO $ print ds
237+ MkFix2 <$> traverse fullTraversal ds
218238
219239-- | Print a warning if source file (first argument) is newer than the binary (second argument)
220240warnIfNewer :: FilePath -> FilePath -> IO ()
0 commit comments