@@ -25,28 +25,34 @@ import Data.List
25
25
import Data.String.Conversions (cs )
26
26
import Text.PrettyPrint.ANSI.Leijen (pretty , plain )
27
27
import Codec.Archive.Zip (withArchive , unEntrySelector , getEntries )
28
+ import Data.IntSet ( IntSet )
29
+ import qualified Data.IntSet as IntSet
28
30
import qualified Data.Set as Set
29
31
import Control.Arrow
30
32
import Data.IORef
31
33
import Control.Exception hiding (catch )
32
34
import Control.Monad.IO.Class (liftIO )
33
35
import Control.Exception.Lifted (catch )
36
+ import Control.Monad.State.Strict ( gets )
34
37
import Control.Monad
35
38
import Data.Aeson ( Value (Null ), FromJSON )
36
39
import qualified Data.IntMap.Strict as I
37
40
import qualified Data.Map.Strict as M
41
+ import Data.Map.Strict ( Map )
38
42
import qualified Data.Text.Encoding as T
39
43
import Data.Text ( Text )
40
44
import qualified Data.Text as T
41
45
import Data.Typeable ( typeOf )
42
- import Data.Maybe ( fromMaybe )
46
+ import Data.Maybe ( fromMaybe , catMaybes )
43
47
import Data.List ( sortOn )
44
48
import GHC.Generics ( Generic )
45
49
import System.Environment ( lookupEnv )
46
50
import System.FilePath ((</>) , takeDirectory , takeExtension , dropExtension , splitFileName )
47
51
import Text.Read ( readMaybe )
48
52
import qualified Data.ByteString.Lazy.Char8 as BL8 ( pack , unpack , fromStrict , toStrict )
49
53
import qualified Control.Concurrent.Chan.Unagi.Bounded as Unagi
54
+ import Control.Concurrent.MVar ( MVar )
55
+ import qualified Control.Concurrent.MVar as MVar
50
56
----------------------------------------------------------------------------
51
57
import Stg.Syntax hiding (sourceName , Scope )
52
58
import Stg.IRLocation
@@ -105,26 +111,62 @@ data AttachArgs
105
111
-- | External STG Interpreter application internal state
106
112
data ESTG
107
113
= 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
111
117
}
112
118
----------------------------------------------------------------------------
113
119
-- | Intialize ESTG interpreter
114
120
----------------------------------------------------------------------------
115
121
initESTG :: AttachArgs -> Adaptor ESTG ()
116
122
initESTG 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
+ }
120
137
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
+
128
170
----------------------------------------------------------------------------
129
171
-- | Exception Handler
130
172
handleDebuggerExceptions :: SomeException -> Adaptor ESTG ()
@@ -136,17 +178,6 @@ handleDebuggerExceptions e = do
136
178
sendTerminatedEvent (TerminatedEvent False )
137
179
sendExitedEvent (ExitedEvent 1 )
138
180
139
- sendStop =
140
- sendStoppedEvent $
141
- StoppedEvent
142
- StoppedEventReasonPause
143
- (Just " paused" )
144
- (Just 0 )
145
- False
146
- (Just " starting now?" )
147
- False
148
- []
149
-
150
181
pathToName path =
151
182
case splitFileName (cs path) of
152
183
(init -> moduleName, takeExtension -> " .ghccore" ) ->
@@ -156,6 +187,20 @@ pathToName path =
156
187
(init -> moduleName, takeExtension -> ext) ->
157
188
cs (moduleName <> ext)
158
189
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
+
159
204
----------------------------------------------------------------------------
160
205
-- | Main function where requests are received and Events + Responses are returned.
161
206
-- The core logic of communicating between the client <-> adaptor <-> debugger
@@ -173,32 +218,12 @@ talk CommandAttach = do
173
218
----------------------------------------------------------------------------
174
219
talk CommandContinue = do
175
220
ESTG {.. } <- getDebugSession
176
- send CmdContinue
221
+ sendAndWait CmdContinue
177
222
sendContinueResponse (ContinueResponse True )
178
223
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
-
198
224
----------------------------------------------------------------------------
199
225
talk CommandConfigurationDone = do
200
226
sendConfigurationDoneResponse
201
- sendStop
202
227
----------------------------------------------------------------------------
203
228
talk CommandDisconnect = do
204
229
destroyDebugSession
@@ -326,6 +351,7 @@ talk CommandPause = sendPauseResponse
326
351
talk CommandSetBreakpoints = do
327
352
SetBreakpointsArguments {.. } <- getArguments
328
353
let maybeSourceRef = sourceSourceReference setBreakpointsArgumentsSource
354
+ clearBreakpoints
329
355
case (setBreakpointsArgumentsBreakpoints, maybeSourceRef) of
330
356
(Just sourceBreakpoints, Just sourceRef) -> do
331
357
(_sourceCodeText, locations) <- getSourceFromFullPak sourceRef
@@ -357,14 +383,16 @@ talk CommandSetBreakpoints = do
357
383
case sortOn snd relevantLocations of
358
384
(stgPoint@ (SP_RhsClosureExpr closureName), ((startRow, startCol), (endRow, endCol))) : _ -> do
359
385
let hitCount = fromMaybe 0 (sourceBreakpointHitCondition >>= readMaybe . T. unpack) :: Int
360
- send (CmdAddBreakpoint closureName hitCount)
386
+ sendAndWait (CmdAddBreakpoint closureName hitCount)
387
+ bkpId <- addNewBreakpoint stgPoint
361
388
pure $ defaultBreakpoint
362
389
{ breakpointVerified = True
363
390
, breakpointSource = Just setBreakpointsArgumentsSource
364
391
, breakpointLine = Just startRow
365
392
, breakpointColumn = Just startCol
366
393
, breakpointEndLine = Just endRow
367
394
, breakpointEndColumn = Just endCol
395
+ , breakpointId = Just bkpId
368
396
}
369
397
_ ->
370
398
pure $ defaultBreakpoint
@@ -429,12 +457,7 @@ talk CommandVariables = do
429
457
talk CommandNext = do
430
458
NextArguments {.. } <- getArguments
431
459
sendAndWait CmdStep
432
- resetObjectLifetimes
433
- sendStoppedEvent defaultStoppedEvent
434
- { stoppedEventReason = StoppedEventReasonStep
435
- , stoppedEventText = Just " Stepping..."
436
- , stoppedEventThreadId = Just 0
437
- }
460
+ pure ()
438
461
----------------------------------------------------------------------------
439
462
talk CommandBreakpointLocations = sendBreakpointLocationsResponse []
440
463
talk CommandSetDataBreakpoints = sendSetDataBreakpointsResponse []
@@ -508,21 +531,14 @@ getSourceFromFullPak sourceId = do
508
531
ir <- readModpakS fullPakPath sourcePath T. decodeUtf8
509
532
pure (ir, [] )
510
533
----------------------------------------------------------------------------
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
- ----------------------------------------------------------------------------
519
534
-- | Synchronous call to Debugger, sends message and waits for response
520
535
sendAndWait :: DebugCommand -> Adaptor ESTG DebugOutput
521
536
sendAndWait cmd = do
522
537
ESTG {.. } <- getDebugSession
538
+ let DebuggerChan {.. } = debuggerChan
523
539
liftIO $ do
524
- Unagi. writeChan inChan cmd
525
- Unagi. readChan outChan
540
+ MVar. putMVar dbgSyncRequest cmd
541
+ MVar. takeMVar dbgSyncResponse
526
542
----------------------------------------------------------------------------
527
543
-- | Receive Thread Report
528
544
-- Fails if anything but 'DbgOutThreadReport' is returned
0 commit comments