@@ -25,28 +25,34 @@ import Data.List
2525import Data.String.Conversions (cs )
2626import Text.PrettyPrint.ANSI.Leijen (pretty , plain )
2727import Codec.Archive.Zip (withArchive , unEntrySelector , getEntries )
28+ import Data.IntSet ( IntSet )
29+ import qualified Data.IntSet as IntSet
2830import qualified Data.Set as Set
2931import Control.Arrow
3032import Data.IORef
3133import Control.Exception hiding (catch )
3234import Control.Monad.IO.Class (liftIO )
3335import Control.Exception.Lifted (catch )
36+ import Control.Monad.State.Strict ( gets )
3437import Control.Monad
3538import Data.Aeson ( Value (Null ), FromJSON )
3639import qualified Data.IntMap.Strict as I
3740import qualified Data.Map.Strict as M
41+ import Data.Map.Strict ( Map )
3842import qualified Data.Text.Encoding as T
3943import Data.Text ( Text )
4044import qualified Data.Text as T
4145import Data.Typeable ( typeOf )
42- import Data.Maybe ( fromMaybe )
46+ import Data.Maybe ( fromMaybe , catMaybes )
4347import Data.List ( sortOn )
4448import GHC.Generics ( Generic )
4549import System.Environment ( lookupEnv )
4650import System.FilePath ((</>) , takeDirectory , takeExtension , dropExtension , splitFileName )
4751import Text.Read ( readMaybe )
4852import qualified Data.ByteString.Lazy.Char8 as BL8 ( pack , unpack , fromStrict , toStrict )
4953import qualified Control.Concurrent.Chan.Unagi.Bounded as Unagi
54+ import Control.Concurrent.MVar ( MVar )
55+ import qualified Control.Concurrent.MVar as MVar
5056----------------------------------------------------------------------------
5157import Stg.Syntax hiding (sourceName , Scope )
5258import Stg.IRLocation
@@ -105,26 +111,62 @@ data AttachArgs
105111-- | External STG Interpreter application internal state
106112data ESTG
107113 = ESTG
108- { inChan :: Unagi. InChan DebugCommand
109- , outChan :: Unagi. OutChan DebugOutput
110- , fullPakPath :: String
114+ { debuggerChan :: DebuggerChan
115+ , fullPakPath :: String
116+ , breakpointMap :: Map StgPoint IntSet
111117 }
112118----------------------------------------------------------------------------
113119-- | Intialize ESTG interpreter
114120----------------------------------------------------------------------------
115121initESTG :: AttachArgs -> Adaptor ESTG ()
116122initESTG AttachArgs {.. } = do
117- (dbgCmdI, dbgCmdO) <- liftIO (Unagi. newChan 100 )
118- (dbgOutI, dbgOutO) <- liftIO (Unagi. newChan 100 )
119- let dbgChan = DebuggerChan (dbgCmdO, dbgOutI)
123+ (dbgAsyncI, dbgAsyncO) <- liftIO (Unagi. newChan 100 )
124+ dbgRequestMVar <- liftIO MVar. newEmptyMVar
125+ dbgResponseMVar <- liftIO MVar. newEmptyMVar
126+ let dbgChan = DebuggerChan
127+ { dbgSyncRequest = dbgRequestMVar
128+ , dbgSyncResponse = dbgResponseMVar
129+ , dbgAsyncEventIn = dbgAsyncI
130+ , dbgAsyncEventOut = dbgAsyncO
131+ }
132+ estg = ESTG
133+ { debuggerChan = dbgChan
134+ , fullPakPath = program
135+ , breakpointMap = mempty
136+ }
120137 flip catch handleDebuggerExceptions
121- $ registerNewDebugSession __sessionId (ESTG dbgCmdI dbgOutO program)
122- (liftIO $ loadAndRunProgram True True program [] dbgChan DbgStepByStep False defaultDebugSettings)
123- (pure () )
124- -- (forever $ do
125- -- message <- liftIO (Unagi.readChan dbgOutO)
126- -- -- logic goes here for conversion to 'OutputEvent'
127- -- sendOutputEvent defaultOutputEvent)
138+ $ registerNewDebugSession __sessionId estg
139+ (loadAndRunProgram True True program [] dbgChan DbgStepByStep False defaultDebugSettings)
140+ (handleDebugEvents dbgChan)
141+
142+ ----------------------------------------------------------------------------
143+ -- | Debug Event Handler
144+ handleDebugEvents :: DebuggerChan -> (Adaptor ESTG () -> IO () ) -> IO ()
145+ handleDebugEvents DebuggerChan {.. } withAdaptor = forever $ do
146+ dbgEvent <- liftIO (Unagi. readChan dbgAsyncEventOut)
147+ withAdaptor $ do
148+ ESTG {.. } <- getDebugSession
149+ let sendEvent ev = sendSuccesfulEvent ev . setBody
150+ case dbgEvent of
151+ DbgEventStopped -> do
152+ resetObjectLifetimes
153+ sendEvent EventTypeStopped $ object
154+ [ " reason" .= String " step"
155+ , " allThreadsStopped" .= True
156+ ]
157+
158+ DbgEventHitBreakpoint bkpName -> do
159+ resetObjectLifetimes
160+ sendEvent EventTypeStopped . object $
161+ [ " reason" .= String " breakpoint"
162+ , " allThreadsStopped" .= True
163+ ] ++
164+ catMaybes
165+ [ do
166+ idSet <- M. lookup (SP_RhsClosureExpr bkpName) breakpointMap
167+ Just (" hitBreakpointIds" .= idSet)
168+ ]
169+
128170----------------------------------------------------------------------------
129171-- | Exception Handler
130172handleDebuggerExceptions :: SomeException -> Adaptor ESTG ()
@@ -136,17 +178,6 @@ handleDebuggerExceptions e = do
136178 sendTerminatedEvent (TerminatedEvent False )
137179 sendExitedEvent (ExitedEvent 1 )
138180
139- sendStop =
140- sendStoppedEvent $
141- StoppedEvent
142- StoppedEventReasonPause
143- (Just " paused" )
144- (Just 0 )
145- False
146- (Just " starting now?" )
147- False
148- []
149-
150181pathToName path =
151182 case splitFileName (cs path) of
152183 (init -> moduleName, takeExtension -> " .ghccore" ) ->
@@ -156,6 +187,20 @@ pathToName path =
156187 (init -> moduleName, takeExtension -> ext) ->
157188 cs (moduleName <> ext)
158189
190+ ----------------------------------------------------------------------------
191+ -- | Clears the currently known breakpoint set
192+ clearBreakpoints :: Adaptor ESTG ()
193+ clearBreakpoints = do
194+ updateDebugSession $ \ estg -> estg {breakpointMap = mempty }
195+
196+ ----------------------------------------------------------------------------
197+ -- | Adds new BreakpointId for a givent StgPoint
198+ addNewBreakpoint :: StgPoint -> Adaptor ESTG BreakpointId
199+ addNewBreakpoint stgPoint = do
200+ bkpId <- getNextBreakpointId
201+ updateDebugSession $ \ estg@ ESTG {.. } -> estg {breakpointMap = M. insertWith mappend stgPoint (IntSet. singleton bkpId) breakpointMap}
202+ pure bkpId
203+
159204----------------------------------------------------------------------------
160205-- | Main function where requests are received and Events + Responses are returned.
161206-- The core logic of communicating between the client <-> adaptor <-> debugger
@@ -173,32 +218,12 @@ talk CommandAttach = do
173218----------------------------------------------------------------------------
174219talk CommandContinue = do
175220 ESTG {.. } <- getDebugSession
176- send CmdContinue
221+ sendAndWait CmdContinue
177222 sendContinueResponse (ContinueResponse True )
178223
179- ESTG {.. } <- getDebugSession
180- _ <- liftIO $ Unagi. readChan outChan
181- resetObjectLifetimes
182- sendStoppedEvent defaultStoppedEvent
183- { stoppedEventReason = StoppedEventReasonBreakpoint
184- , stoppedEventThreadId = Just 0
185- }
186- {-
187- data StoppedEvent
188- = StoppedEvent
189- { stoppedEventReason :: StoppedEventReason
190- , stoppedEventDescription :: Maybe Text
191- , stoppedEventThreadId :: Maybe Int
192- , stoppedEventPreserveFocusHint :: Bool
193- , stoppedEventText :: Maybe Text
194- , stoppedEventAllThreadsStopped :: Bool
195- , stoppedEventHitBreakpointIds :: [Int]
196- -}
197-
198224----------------------------------------------------------------------------
199225talk CommandConfigurationDone = do
200226 sendConfigurationDoneResponse
201- sendStop
202227----------------------------------------------------------------------------
203228talk CommandDisconnect = do
204229 destroyDebugSession
@@ -326,6 +351,7 @@ talk CommandPause = sendPauseResponse
326351talk CommandSetBreakpoints = do
327352 SetBreakpointsArguments {.. } <- getArguments
328353 let maybeSourceRef = sourceSourceReference setBreakpointsArgumentsSource
354+ clearBreakpoints
329355 case (setBreakpointsArgumentsBreakpoints, maybeSourceRef) of
330356 (Just sourceBreakpoints, Just sourceRef) -> do
331357 (_sourceCodeText, locations) <- getSourceFromFullPak sourceRef
@@ -357,14 +383,16 @@ talk CommandSetBreakpoints = do
357383 case sortOn snd relevantLocations of
358384 (stgPoint@ (SP_RhsClosureExpr closureName), ((startRow, startCol), (endRow, endCol))) : _ -> do
359385 let hitCount = fromMaybe 0 (sourceBreakpointHitCondition >>= readMaybe . T. unpack) :: Int
360- send (CmdAddBreakpoint closureName hitCount)
386+ sendAndWait (CmdAddBreakpoint closureName hitCount)
387+ bkpId <- addNewBreakpoint stgPoint
361388 pure $ defaultBreakpoint
362389 { breakpointVerified = True
363390 , breakpointSource = Just setBreakpointsArgumentsSource
364391 , breakpointLine = Just startRow
365392 , breakpointColumn = Just startCol
366393 , breakpointEndLine = Just endRow
367394 , breakpointEndColumn = Just endCol
395+ , breakpointId = Just bkpId
368396 }
369397 _ ->
370398 pure $ defaultBreakpoint
@@ -429,12 +457,7 @@ talk CommandVariables = do
429457talk CommandNext = do
430458 NextArguments {.. } <- getArguments
431459 sendAndWait CmdStep
432- resetObjectLifetimes
433- sendStoppedEvent defaultStoppedEvent
434- { stoppedEventReason = StoppedEventReasonStep
435- , stoppedEventText = Just " Stepping..."
436- , stoppedEventThreadId = Just 0
437- }
460+ pure ()
438461----------------------------------------------------------------------------
439462talk CommandBreakpointLocations = sendBreakpointLocationsResponse []
440463talk CommandSetDataBreakpoints = sendSetDataBreakpointsResponse []
@@ -508,21 +531,14 @@ getSourceFromFullPak sourceId = do
508531 ir <- readModpakS fullPakPath sourcePath T. decodeUtf8
509532 pure (ir, [] )
510533----------------------------------------------------------------------------
511- -- | Asynchronous call to Debugger, sends message, does not wait for response
512- send
513- :: DebugCommand
514- -> Adaptor ESTG ()
515- send cmd = do
516- ESTG {.. } <- getDebugSession
517- liftIO (Unagi. writeChan inChan cmd)
518- ----------------------------------------------------------------------------
519534-- | Synchronous call to Debugger, sends message and waits for response
520535sendAndWait :: DebugCommand -> Adaptor ESTG DebugOutput
521536sendAndWait cmd = do
522537 ESTG {.. } <- getDebugSession
538+ let DebuggerChan {.. } = debuggerChan
523539 liftIO $ do
524- Unagi. writeChan inChan cmd
525- Unagi. readChan outChan
540+ MVar. putMVar dbgSyncRequest cmd
541+ MVar. takeMVar dbgSyncResponse
526542----------------------------------------------------------------------------
527543-- | Receive Thread Report
528544-- Fails if anything but 'DbgOutThreadReport' is returned
0 commit comments