Fix a bug in the closure viewer
[ghc-hetmet.git] / compiler / ghci / Debugger.hs
1 -----------------------------------------------------------------------------
2 --
3 -- GHCi Interactive debugging commands 
4 --
5 -- Pepe Iborra (supported by Google SoC) 2006
6 --
7 -----------------------------------------------------------------------------
8
9 module Debugger where
10
11 import Linker
12 import Breakpoints
13 import RtClosureInspect
14
15 import PrelNames
16 import HscTypes
17 import IdInfo
18 --import Id
19 import Var hiding ( varName )
20 import VarSet
21 import VarEnv
22 import Name 
23 import NameEnv
24 import RdrName
25 import Module
26 import Finder
27 import UniqSupply
28 import Type
29 import TyCon
30 import DataCon
31 import TcGadt
32 import GHC
33 import GhciMonad
34 import PackageConfig
35
36 import Outputable
37 import ErrUtils
38 import FastString
39 import SrcLoc
40 import Util
41 import Maybes
42
43 import Control.Exception
44 import Control.Monad
45 import qualified Data.Map as Map
46 import Data.Array.Unboxed
47 import Data.Typeable             ( Typeable )
48 import Data.Maybe
49 import Data.IORef
50
51 import System.IO
52 import GHC.Exts
53
54 #include "HsVersions.h"
55
56 -------------------------------------
57 -- | The :print & friends commands
58 -------------------------------------
59 pprintClosureCommand :: Bool -> Bool -> String -> GHCi ()
60 pprintClosureCommand bindThings force str = do
61   cms <- getSession 
62   let strs = words str
63   mbThings <- io$ ( mapM (GHC.lookupName cms) =<<) 
64                   . liftM concat 
65                   . mapM (GHC.parseName cms) 
66                    $ strs
67   newvarsNames <- io$ do 
68            uniques <- liftM uniqsFromSupply (mkSplitUniqSupply 'q')
69            return$ map (\u-> (mkSysTvName u (mkFastString "a"))) uniques
70   let ids_ = [id | Just (AnId id) <- mbThings]
71
72   -- Clean up 'Unknown' types artificially injected into tyvars 
73       ids = map (stripUnknowns newvarsNames) ids_
74  
75  -- Obtain the terms 
76   mb_terms  <- io$ mapM (obtainTerm cms force) ids
77
78   -- Give names to suspensions and bind them in the local env
79   mb_terms' <- if bindThings
80                then io$ mapM (fmapMMaybe (bindSuspensions cms)) mb_terms
81                else return mb_terms
82   ppr_terms <- io$ mapM (fmapMMaybe (printTerm cms)) mb_terms' 
83   let docs = [ ppr id <+> char '=' <+> t | (Just t,id) <- zip ppr_terms ids]
84   unqual  <- io$ GHC.getPrintUnqual cms
85   io . putStrLn . showSDocForUser unqual $ Outputable.vcat docs
86
87   -- Type reconstruction may have obtained more defined types for some ids
88   -- So we refresh their types.
89   let new_ids0 = [ setIdType id ty | (id,Just t) <- zip ids mb_terms
90                                    , let Just ty = termType t
91                                    , ty `isMoreSpecificThan` idType id 
92                                    ]
93   new_ids <- io$ mapM (\x->liftM (setIdType x) . instantiateTyVarsToUnknown cms . idType $ x) 
94                       new_ids0   
95   let Session ref = cms
96   hsc_env <- io$ readIORef ref
97   let ictxt = hsc_IC hsc_env
98       type_env = ic_type_env ictxt
99       filtered_type_env = delListFromNameEnv type_env (map idName new_ids)
100       new_type_env =  extendTypeEnvWithIds filtered_type_env new_ids
101       new_ic = ictxt {ic_type_env = new_type_env }
102   io$ writeIORef ref (hsc_env {hsc_IC = new_ic })
103                                           
104   where
105     isMoreSpecificThan :: Type -> Type -> Bool
106     ty `isMoreSpecificThan   ` ty1 
107       | Just subst    <- tcUnifyTys bindOnlyTy1 [repType' ty] [repType' ty1] 
108       , substFiltered <- filter (not.isTyVarTy) . varEnvElts . getTvSubstEnv $ subst
109       , not . null $ substFiltered
110       , all (flip notElemTvSubst subst) ty_vars
111       = True
112       | otherwise = False
113       where bindOnlyTy1 tyv | tyv `elem` ty_vars = AvoidMe
114                             | otherwise = BindMe
115             ty_vars = varSetElems$ tyVarsOfType ty
116
117     bindSuspensions :: Session -> Term -> IO Term
118     bindSuspensions cms@(Session ref) t = do 
119       hsc_env <- readIORef ref
120       inScope <- GHC.getBindings cms
121       let ictxt        = hsc_IC hsc_env
122           rn_env       = ic_rn_local_env ictxt
123           type_env     = ic_type_env ictxt
124           prefix       = "_t"
125           alreadyUsedNames = map (occNameString . nameOccName . getName) inScope
126           availNames   = [n | n <- map ((prefix++) . show) [1..]
127                             , n `notElem` alreadyUsedNames ]
128       availNames_var  <- newIORef availNames
129       (t', stuff)     <- foldTerm (nameSuspensionsAndGetInfos availNames_var) t
130       let (names, tys, hvals) = unzip3 stuff
131       concrete_tys    <- mapM (instantiateTyVarsToUnknown cms) tys
132       let ids = [ mkGlobalId VanillaGlobal name ty vanillaIdInfo
133                   | (name,ty) <- zip names concrete_tys]
134           new_type_env = extendTypeEnvWithIds type_env ids 
135           new_rn_env   = extendLocalRdrEnv rn_env names
136           new_ic       = ictxt { ic_rn_local_env = new_rn_env, 
137                                  ic_type_env     = new_type_env }
138       extendLinkEnv (zip names hvals)
139       writeIORef ref (hsc_env {hsc_IC = new_ic })
140       return t'
141      where    
142
143 --    Processing suspensions. Give names and recopilate info
144         nameSuspensionsAndGetInfos :: IORef [String] -> TermFold (IO (Term, [(Name,Type,HValue)]))
145         nameSuspensionsAndGetInfos freeNames = TermFold 
146                       {
147                         fSuspension = doSuspension freeNames
148                       , fTerm = \ty dc v tt -> do 
149                                     tt' <- sequence tt 
150                                     let (terms,names) = unzip tt' 
151                                     return (Term ty dc v terms, concat names)
152                       , fPrim    = \ty n ->return (Prim ty n,[])
153                       }
154         doSuspension freeNames ct mb_ty hval Nothing = do
155           name <- atomicModifyIORef freeNames (\x->(tail x, head x))
156           n <- newGrimName cms name
157           let ty' = fromMaybe (error "unexpected") mb_ty
158           return (Suspension ct mb_ty hval (Just n), [(n,ty',hval)])
159
160
161 --  A custom Term printer to enable the use of Show instances
162     printTerm cms@(Session ref) = customPrintTerm customPrint
163       where
164         customPrint = \p-> customPrintShowable : customPrintTermBase p 
165         customPrintShowable t@Term{ty=ty, dc=dc, val=val} = do
166           let hasType = isEmptyVarSet (tyVarsOfType ty)  -- redundant
167               isEvaled = isFullyEvaluatedTerm t
168           if isEvaled -- && hasType
169            then do 
170               hsc_env <- readIORef ref
171               dflags  <- GHC.getSessionDynFlags cms
172               do
173                    (new_env, bname) <- bindToFreshName hsc_env ty "showme"
174                    writeIORef ref (new_env)
175                    let noop_log _ _ _ _ = return () 
176                        expr = "show " ++ showSDoc (ppr bname)
177                    GHC.setSessionDynFlags cms dflags{log_action=noop_log}
178                    mb_txt <- withExtendedLinkEnv [(bname, val)] 
179                                (GHC.compileExpr cms expr)
180                    case mb_txt of 
181                      Just txt -> return . Just . text . unsafeCoerce# $ txt
182                      Nothing  -> return Nothing
183                `finally` do 
184                    writeIORef ref hsc_env
185                    GHC.setSessionDynFlags cms dflags
186            else return Nothing
187
188         bindToFreshName hsc_env ty userName = do
189           name <- newGrimName cms userName 
190           let ictxt    = hsc_IC hsc_env
191               rn_env   = ic_rn_local_env ictxt
192               type_env = ic_type_env ictxt
193               id       = mkGlobalId VanillaGlobal name ty vanillaIdInfo
194               new_type_env = extendTypeEnv type_env (AnId id)
195               new_rn_env   = extendLocalRdrEnv rn_env [name]
196               new_ic       = ictxt { ic_rn_local_env = new_rn_env, 
197                                      ic_type_env     = new_type_env }
198           return (hsc_env {hsc_IC = new_ic }, name)
199 --    Create new uniques and give them sequentially numbered names
200 --    newGrimName :: Session -> String -> IO Name
201     newGrimName cms userName  = do
202       us <- mkSplitUniqSupply 'b'
203       let unique  = uniqFromSupply us
204           occname = mkOccName varName userName
205           name    = mkInternalName unique occname noSrcLoc
206       return name
207
208 ----------------------------------------------------------------------------
209 -- | Replace all the tyvars in a Term with the opaque type GHC.Base.Unknown
210 ----------------------------------------------------------------------------
211 instantiateTyVarsToUnknown :: Session -> Type -> IO Type
212 instantiateTyVarsToUnknown cms ty
213 -- We have a GADT, so just fix its tyvars
214     | Just (tycon, args) <- splitTyConApp_maybe ty
215     , tycon /= funTyCon
216     , isGADT tycon
217     = mapM fixTyVars args >>= return . mkTyConApp tycon
218 -- We have a regular TyCon, so map recursively to its args
219     | Just (tycon, args) <- splitTyConApp_maybe ty
220     , tycon /= funTyCon
221     = do unknownTyVar <- unknownTV
222          args' <- mapM (instantiateTyVarsToUnknown cms) args
223          return$ mkTyConApp tycon args'
224 -- we have a tyvar of kind *
225     | Just tyvar <- getTyVar_maybe ty
226     , ([],_) <- splitKindFunTys (tyVarKind tyvar) 
227     = unknownTV
228 -- we have a higher kind tyvar, so insert an unknown of the appropriate kind
229     | Just tyvar <- getTyVar_maybe ty
230     , (args,_) <- splitKindFunTys (tyVarKind tyvar)
231     = liftM mkTyConTy $ unknownTC !! length args
232 -- Base case
233     | otherwise    = return ty 
234
235  where unknownTV = do 
236          Just (ATyCon unknown_tc) <- lookupName cms unknownTyConName
237          return$ mkTyConTy unknown_tc
238        unknownTC = [undefined, unknownTC1, unknownTC2, unknownTC3]
239        unknownTC1 = do 
240          Just (ATyCon unknown_tc) <- lookupName cms unknown1TyConName
241          return unknown_tc
242        unknownTC2 = do 
243          Just (ATyCon unknown_tc) <- lookupName cms unknown2TyConName
244          return unknown_tc
245        unknownTC3 = do 
246          Just (ATyCon unknown_tc) <- lookupName cms unknown3TyConName
247          return unknown_tc
248 --       isGADT ty | pprTrace' "isGADT" (ppr ty <> colon <> ppr(isGadtSyntaxTyCon ty)) False = undefined
249        isGADT tc | Just dcs <- tyConDataCons_maybe tc = any (not . null . dataConEqSpec) dcs
250                  | otherwise = False
251        fixTyVars ty 
252            | Just (tycon, args) <- splitTyConApp_maybe ty
253            = mapM fixTyVars args >>= return . mkTyConApp tycon
254 -- Fix the tyvar so that the interactive environment doesn't choke on it TODO 
255            | Just tv <- getTyVar_maybe ty = return ty --TODO
256            | otherwise = return ty
257
258 -- | The inverse function. Strip the GHC.Base.Unknowns in the type of the id, they correspond to tyvars. The caller must provide an infinite list of fresh names
259 stripUnknowns :: [Name] -> Id -> Id
260 stripUnknowns names id = setIdType id . sigmaType . fst . go names . idType 
261                            $ id
262  where 
263    go tyvarsNames@(v:vv) ty 
264     | Just (ty1,ty2) <- splitFunTy_maybe ty = let
265                (ty1',vv') = go tyvarsNames ty1
266                (ty2',vv'')= go vv' ty2
267                in (mkFunTy ty1' ty2', vv'')
268     | Just (ty1,ty2) <- splitAppTy_maybe ty = let
269                (ty1',vv') = go tyvarsNames ty1
270                (ty2',vv'')= go vv' ty2
271                in (mkAppTy ty1' ty2', vv'')
272     | Just (tycon, args) <- splitTyConApp_maybe ty 
273     , Just (tycon', vv') <- (fixTycon tycon tyvarsNames)
274     , (args',vv'') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg 
275                                              in (arg':aa,vv'))
276                             ([],vv') args
277     = (mkAppTys tycon' args',vv'')
278     | Just (tycon, args) <- splitTyConApp_maybe ty
279     , (args',vv') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg 
280                                             in (arg':aa,vv'))
281                            ([],tyvarsNames) args
282     = (mkTyConApp tycon args',vv')
283     | otherwise = (ty, tyvarsNames)
284     where  fixTycon tycon (v:vv) = do
285                k <- lookup (tyConName tycon) kinds
286                return (mkTyVarTy$ mkTyVar v k, vv)
287            kinds = [ (unknownTyConName, liftedTypeKind)
288                    , (unknown1TyConName, kind1)
289                    , (unknown2TyConName, kind2)
290                    , (unknown3TyConName, kind3)]
291            kind1 = mkArrowKind liftedTypeKind liftedTypeKind
292            kind2 = mkArrowKind kind1 liftedTypeKind
293            kind3 = mkArrowKind kind2 liftedTypeKind
294 stripUnknowns _ id = id
295
296 -----------------------------
297 -- | The :breakpoint command
298 -----------------------------
299 bkptOptions :: String -> GHCi Bool
300 bkptOptions "continue" = -- We want to quit if in an inferior session
301                          liftM not isTopLevel 
302 bkptOptions "stop" = do
303   inside_break <- liftM not isTopLevel
304   when inside_break $ throwDyn StopChildSession 
305   return False
306
307 bkptOptions cmd = do 
308   dflags <- getDynFlags
309   bt     <- getBkptTable
310   sess   <- getSession
311   bkptOptions' sess (words cmd) bt
312   return False
313    where
314     bkptOptions' _ ["list"] bt = do 
315       let msgs = [ ppr mod <+> colon <+> ppr coords 
316                    | (mod,site) <- btList bt
317                    , let coords = getSiteCoords bt mod site]
318           num_msgs = [parens (int n) <+> msg | (n,msg) <- zip [1..] msgs]
319       msg <- showForUser$ if null num_msgs 
320                             then text "There are no enabled breakpoints"
321                             else vcat num_msgs
322       io$ putStrLn msg
323
324     bkptOptions' s ("add":cmds) bt 
325       | [mod_name,line]<- cmds
326       , [(lineNum,[])] <- reads line
327       =  handleAdd mod_name $ (\mod->addBkptByLine mod lineNum)
328
329       | [mod_name,line,col] <- cmds
330       = handleAdd mod_name $ (\mod->addBkptByCoord mod (read line, read col))
331
332       | otherwise = throwDyn $ CmdLineError $ 
333                        "syntax: :breakpoint add Module line [col]"
334        where 
335          handleAdd mod_name f = do
336            mod         <- io$ GHC.findModule s (GHC.mkModuleName mod_name) Nothing
337            ghciHandleDyn (handleBkptEx s mod) $
338             case f mod bt of
339              (newTable, site)  -> do
340                setBkptTable newTable 
341                io (putStrLn ("Breakpoint set at " ++ 
342                               show (getSiteCoords newTable mod site)))
343
344     bkptOptions' s ("del":cmds) bt 
345       | [i']     <- cmds 
346       , [(i,[])] <- reads i'
347       , bkpts    <- btList bt
348       = if i > length bkpts
349            then throwDyn $ CmdLineError 
350               "Not a valid breakpoint #. Use :breakpoint list to see the current breakpoints."
351            else 
352              let (mod, site) = bkpts !! (i-1)
353              in handleDel mod $ delBkptBySite mod site
354
355       | [fn,line]      <- cmds 
356       , [(lineNum,[])] <- reads line
357       , mod            <- GHC.mkModule mainPackageId (GHC.mkModuleName fn)
358       = handleDel mod $  delBkptByLine mod lineNum
359
360       | [fn,line,col]  <- cmds 
361       , [(lineNum,[])] <- reads line
362       , [(colNum,[])]  <- reads col
363       , mod            <- GHC.mkModule mainPackageId (GHC.mkModuleName fn)
364       = handleDel mod $ delBkptByCoord mod (lineNum, colNum)
365         
366       | otherwise = throwDyn $ CmdLineError $ 
367              "syntax: :breakpoint del (breakpoint # | Module line [col])"
368
369        where delMsg = "Breakpoint deleted"
370              handleDel mod f = ghciHandleDyn (handleBkptEx s mod) 
371                                              (modifyBkptTable f >> io (putStrLn delMsg))
372
373     bkptOptions' _ _ _ = throwDyn $ CmdLineError $ 
374                          "syntax: :breakpoint (list|continue|stop|add|del)"
375
376 -- Error messages
377 --    handleBkptEx :: Session -> Module -> Debugger.BkptException -> a
378     handleBkptEx _ _ NoBkptFound = error "No suitable breakpoint site found"  
379          -- ^ TODO Instead of complaining, set a bkpt in the next suitable line
380     handleBkptEx _ _ NotNeeded   = error "Nothing to do"
381     handleBkptEx s m NotHandled  = io$
382                                    findModSummary m                  >>= \mod_summary ->
383                                    isModuleInterpreted s mod_summary >>= \it -> 
384        if it
385         then error$ "Module " ++ showSDoc (ppr m) ++  " was not loaded under debugging mode.\n" 
386                  ++ "Enable debugging mode with -fdebugging (and reload your module)"
387         else error$ "Module " ++ showSDoc (ppr m) ++  " was loaded in compiled (.o) mode.\n" 
388                  ++ "You must load a module in interpreted mode and with -fdebugging on to debug it."
389                      where findModSummary m = getModuleGraph s >>= \mod_graph ->  
390                                case [ modsum | modsum <- mod_graph
391                                              , ms_mod modsum == m ] of
392                                  [modsum] -> return modsum
393
394 -------------------------
395 -- Breakpoint Tables
396 -------------------------
397
398 data BkptTable a  = BkptTable { 
399                            -- | An array of breaks, indexed by site number
400      breakpoints :: Map.Map a (UArray Int Bool)  
401                            -- | A list of lines, each line can have zero or more sites, which are annotated with a column number
402    , sites       :: Map.Map a [[(SiteNumber, Int)]] 
403    }
404
405 sitesOf :: Ord a => BkptTable a -> a -> Maybe [[(SiteNumber, Int)]] 
406 sitesOf bt fn = Map.lookup fn (sites bt)
407 bkptsOf bt fn = Map.lookup fn (breakpoints bt)
408
409
410 -- The functions for manipulating BkptTables do throw exceptions
411 data BkptException =
412                     NotHandled
413                   | NoBkptFound
414                   | NotNeeded   -- Used when a breakpoint was already enabled
415   deriving Typeable
416
417 emptyBkptTable :: Ord a => BkptTable a
418 addModule      :: Ord a => a -> [(SiteNumber,Coord)] -> BkptTable a -> BkptTable a
419 -- | Lines start at index 1
420 addBkptByLine  :: Ord a => a -> Int        -> BkptTable a -> (BkptTable a, SiteNumber)
421 addBkptByCoord :: Ord a => a -> Coord      -> BkptTable a -> (BkptTable a, SiteNumber)
422 delBkptByLine  :: Ord a => a -> Int        -> BkptTable a -> BkptTable a
423 delBkptBySite  :: Ord a => a -> SiteNumber -> BkptTable a -> BkptTable a
424 delBkptByCoord :: Ord a => a -> Coord      -> BkptTable a -> BkptTable a
425
426 isBkptEnabled  :: Ord a => BkptTable a -> BkptLocation a -> Bool
427 btElems        :: Ord a => BkptTable a -> [(a, [SiteNumber])]
428 btList         :: Ord a => BkptTable a -> [BkptLocation a]
429 sitesList      :: Ord a => BkptTable a -> [(a, [Coord])]
430 getSiteCoords  :: Ord a => BkptTable a -> a -> SiteNumber -> Coord
431
432 emptyBkptTable = BkptTable Map.empty Map.empty
433
434 addBkptByLine a i bt
435    | Just lines    <- sitesOf bt a
436    , Just bkptsArr <- bkptsOf bt a
437    , i < length lines
438    = case lines!!i of 
439        []    -> throwDyn NoBkptFound
440        (x:_) -> let (siteNum,col) = x
441                     wasAlreadyOn  = bkptsArr ! siteNum
442                     newArr        = bkptsArr // [(siteNum, True)]
443                     newTable      = Map.insert a newArr (breakpoints bt)
444         in if wasAlreadyOn 
445            then throwDyn NotNeeded
446            else (bt{breakpoints=newTable}, siteNum)
447
448    | Just sites    <- sitesOf bt a
449    = throwDyn NoBkptFound
450    | otherwise     = throwDyn NotHandled  
451
452 addBkptByCoord a (r,c) bt 
453    | Just lines    <- sitesOf bt a
454    , Just bkptsArr <- bkptsOf bt a
455    , r < length lines
456        = case [ (sn,col) | (sn,col)<-lines!!r, col>=c] of 
457        []    -> throwDyn NoBkptFound
458        (x:_) -> let (siteNum, col) = x
459                     wasAlreadyOn  = bkptsArr ! siteNum
460                     newArr        = bkptsArr // [(siteNum, True)]
461                     newTable      = Map.insert a newArr (breakpoints bt)
462         in if wasAlreadyOn 
463            then throwDyn NotNeeded
464            else (bt{breakpoints=newTable}, siteNum)
465
466    | Just sites    <- sitesOf bt a
467    = throwDyn NoBkptFound
468    | otherwise     = throwDyn NotHandled  
469
470 delBkptBySite a i bt 
471    | Just bkptsArr <- bkptsOf bt a
472    , not (inRange (bounds bkptsArr) i)
473    = throwDyn NoBkptFound
474
475    | Just bkptsArr <- bkptsOf bt a
476    , bkptsArr ! i     -- Check that there was a enabled bkpt here 
477    , newArr        <- bkptsArr // [(i,False)] 
478    , newTable      <- Map.insert a newArr (breakpoints bt)
479    = bt {breakpoints=newTable}
480
481    | Just sites    <- sitesOf bt a
482    = throwDyn NotNeeded
483
484    | otherwise = throwDyn NotHandled
485
486 delBkptByLine a l bt 
487    | Just sites    <- sitesOf bt a
488    , (site:_)      <- [s | (s,c') <- sites !! l]
489    = delBkptBySite a site bt
490
491    | Just sites    <- sitesOf bt a
492    = throwDyn NoBkptFound
493
494    | otherwise = throwDyn NotHandled
495
496 delBkptByCoord a (r,c) bt 
497    | Just sites    <- sitesOf bt a
498    , (site:_)      <- [s | (s,c') <- sites !! r, c>=c', isBkptEnabled bt (a,s)]
499    = delBkptBySite a site bt
500
501    | Just sites    <- sitesOf bt a
502    = throwDyn NoBkptFound
503
504    | otherwise = throwDyn NotHandled
505
506 btElems bt = [ (a, [i | (i,True) <- assocs siteArr])
507              | (a, siteArr) <- Map.assocs (breakpoints bt) ]
508
509 btList bt =  [(a,site) | (a, sites) <- btElems bt, site <- sites] 
510
511 sitesList bt = [ (a, sitesCoords sitesCols) | (a, sitesCols) <- Map.assocs (sites bt) ]
512     where sitesCoords sitesCols = 
513               [ (row,col) 
514                 | (row, cols) <- zip [0..] sitesCols, (_,col) <- cols ] 
515
516 getSiteCoords bt a site 
517    | Just rows <- sitesOf bt a
518    = head [ (r,c) | (r,row) <- zip [0..] rows
519                   , (s,c)   <- row
520                   , s == site ]
521
522 -- addModule is dumb and inefficient, but it does the job
523 addModule a [] bt = bt {sites = Map.insert a [] (sites bt)}
524 addModule a siteCoords bt 
525    | nrows        <- maximum$ [i | (_,(i,j)) <- siteCoords ]
526    , sitesByRow   <- [ [(s,c) | (s,(r,c)) <- siteCoords, r==i] 
527                        | i <- [0..nrows] ]
528    , nsites       <- length siteCoords
529    , initialBkpts <- listArray (1, nsites) (repeat False) 
530    = bt{ sites       = Map.insert a sitesByRow (sites bt) 
531        , breakpoints = Map.insert a initialBkpts (breakpoints bt) }
532
533 isBkptEnabled bt (a,site) 
534    | Just bkpts <- bkptsOf bt a 
535    , inRange (bounds bkpts) site
536    = bkpts ! site 
537    | otherwise = panic "unexpected condition: I don't know that breakpoint site"
538
539 -----------------
540 -- Other stuff
541 -----------------
542 refreshBkptTable :: [ModSummary] -> GHCi ()
543 refreshBkptTable [] = return ()
544 refreshBkptTable (ms:mod_sums) = do
545     sess        <- getSession
546     isDebugging <- io(isDebuggingM sess)
547     when isDebugging $ do
548       old_table <- getBkptTable
549       new_table <- addModuleGHC sess old_table (GHC.ms_mod ms)
550       setBkptTable new_table
551     refreshBkptTable mod_sums
552   where addModuleGHC sess bt mod = do
553           Just mod_info <- io$ GHC.getModuleInfo sess mod
554           dflags <- getDynFlags
555           let sites = GHC.modInfoBkptSites mod_info
556           io$ debugTraceMsg dflags 2 
557                 (ppr mod <> text ": inserted " <> int (length sites) <>
558                  text " breakpoints")
559           return$ addModule mod sites bt
560 #if defined(GHCI) && defined(DEBUGGER)
561         isDebuggingM sess = isModuleInterpreted sess ms >>= \isInterpreted -> 
562                             return (Opt_Debugging `elem` dflags && target == HscInterpreted && isInterpreted)
563         dflags = flags     (GHC.ms_hspp_opts ms)
564         target = hscTarget (GHC.ms_hspp_opts ms)
565 #else
566         isDebuggingM _ = return False
567 #endif