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