Warning police: Removed catch-all case which was overlapped
[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   mb_new_ids <- mapM (io . go cms) (catMaybes mb_ids)
70   io$ updateIds cms (catMaybes mb_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 (Maybe Id)
82    go cms id = do
83      mb_term <- obtainTerm cms force id
84      maybe (return Nothing) `flip` mb_term $ \term -> do
85        term'     <- if not bindThings then return term 
86                      else bindSuspensions cms term                         
87        showterm  <- pprTerm cms term'
88        unqual    <- GHC.getPrintUnqual cms
89        let showSDocForUserOneLine unqual doc = 
90                showDocWith LeftMode (doc (mkErrStyle unqual))
91        (putStrLn . showSDocForUserOneLine unqual) (ppr id <+> char '=' <+> showterm)
92      -- Before leaving, we compare the type obtained to see if it's more specific
93      -- Note how we need the Unknown-clear type returned by obtainTerm
94        let Just reconstructedType = termType term  
95        new_type  <- instantiateTyVarsToUnknown cms 
96                     (mostSpecificType (idType id) reconstructedType)
97        return . Just $ setIdType id new_type
98
99    updateIds :: Session -> [Id] -> IO ()
100    updateIds (Session ref) new_ids = do
101      hsc_env <- readIORef ref
102      let ictxt = hsc_IC hsc_env
103          type_env = ic_type_env ictxt
104          filtered_type_env = delListFromNameEnv type_env (map idName new_ids)
105          new_type_env =  extendTypeEnvWithIds filtered_type_env new_ids
106          new_ic = ictxt {ic_type_env = new_type_env }
107      writeIORef ref (hsc_env {hsc_IC = new_ic })
108
109 isMoreSpecificThan :: Type -> Type -> Bool
110 ty `isMoreSpecificThan` ty1 
111       | Just subst    <- tcUnifyTys bindOnlyTy1 [repType' ty] [repType' ty1] 
112       , substFiltered <- filter (not.isTyVarTy) . varEnvElts . getTvSubstEnv $ subst
113       , not . null $ substFiltered
114       , all (flip notElemTvSubst subst) ty_vars
115       = True
116       | otherwise = False
117       where bindOnlyTy1 tyv | tyv `elem` ty_vars = AvoidMe
118                             | otherwise = BindMe
119             ty_vars = varSetElems$ tyVarsOfType ty
120
121 mostSpecificType ty1 ty2 | ty1 `isMoreSpecificThan` ty2 = ty1
122                          | otherwise = ty2
123
124 -- | Give names, and bind in the interactive environment, to all the suspensions
125 --   included (inductively) in a term
126 bindSuspensions :: Session -> Term -> IO Term
127 bindSuspensions cms@(Session ref) t = do 
128       hsc_env <- readIORef ref
129       inScope <- GHC.getBindings cms
130       let ictxt        = hsc_IC hsc_env
131           rn_env       = ic_rn_local_env ictxt
132           type_env     = ic_type_env ictxt
133           prefix       = "_t"
134           alreadyUsedNames = map (occNameString . nameOccName . getName) inScope
135           availNames   = map ((prefix++) . show) [1..] \\ alreadyUsedNames 
136       availNames_var  <- newIORef availNames
137       (t', stuff)     <- foldTerm (nameSuspensionsAndGetInfos availNames_var) t
138       let (names, tys, hvals) = unzip3 stuff
139       concrete_tys    <- mapM (instantiateTyVarsToUnknown cms) tys
140       let ids = [ mkGlobalId VanillaGlobal name ty vanillaIdInfo
141                   | (name,ty) <- zip names concrete_tys]
142           new_type_env = extendTypeEnvWithIds type_env ids 
143           new_rn_env   = extendLocalRdrEnv rn_env names
144           new_ic       = ictxt { ic_rn_local_env = new_rn_env, 
145                                  ic_type_env     = new_type_env }
146       extendLinkEnv (zip names hvals)
147       writeIORef ref (hsc_env {hsc_IC = new_ic })
148       return t'
149      where    
150
151 --    Processing suspensions. Give names and recopilate info
152         nameSuspensionsAndGetInfos :: IORef [String] -> TermFold (IO (Term, [(Name,Type,HValue)]))
153         nameSuspensionsAndGetInfos freeNames = TermFold 
154                       {
155                         fSuspension = doSuspension freeNames
156                       , fTerm = \ty dc v tt -> do 
157                                     tt' <- sequence tt 
158                                     let (terms,names) = unzip tt' 
159                                     return (Term ty dc v terms, concat names)
160                       , fPrim    = \ty n ->return (Prim ty n,[])
161                       }
162         doSuspension freeNames ct mb_ty hval Nothing = do
163           name <- atomicModifyIORef freeNames (\x->(tail x, head x))
164           n <- newGrimName cms name
165           let ty' = fromMaybe (error "unexpected") mb_ty
166           return (Suspension ct mb_ty hval (Just n), [(n,ty',hval)])
167
168
169 --  A custom Term printer to enable the use of Show instances
170 pprTerm cms@(Session ref) = customPrintTerm customPrint
171  where
172   customPrint = \p-> customPrintShowable : customPrintTermBase p 
173   customPrintShowable t@Term{ty=ty, dc=dc, val=val} = do
174     let hasType = isEmptyVarSet (tyVarsOfType ty)  -- redundant
175         isEvaled = isFullyEvaluatedTerm t
176     if not isEvaled -- || not hasType
177      then return Nothing
178      else do 
179         hsc_env <- readIORef ref
180         dflags  <- GHC.getSessionDynFlags cms
181         do
182            (new_env, bname) <- bindToFreshName hsc_env ty "showme"
183            writeIORef ref (new_env)
184            let noop_log _ _ _ _ = return () 
185                expr = "show " ++ showSDoc (ppr bname)
186            GHC.setSessionDynFlags cms dflags{log_action=noop_log}
187            mb_txt <- withExtendedLinkEnv [(bname, val)] 
188                                          (GHC.compileExpr cms expr)
189            case mb_txt of 
190              Just txt -> return . Just . text . unsafeCoerce# $ txt
191              Nothing  -> return Nothing
192          `finally` do 
193            writeIORef ref hsc_env
194            GHC.setSessionDynFlags cms dflags
195      
196   bindToFreshName hsc_env ty userName = do
197     name <- newGrimName cms userName 
198     let ictxt    = hsc_IC hsc_env
199         rn_env   = ic_rn_local_env ictxt
200         type_env = ic_type_env ictxt
201         id       = mkGlobalId VanillaGlobal name ty vanillaIdInfo
202         new_type_env = extendTypeEnv type_env (AnId id)
203         new_rn_env   = extendLocalRdrEnv rn_env [name]
204         new_ic       = ictxt { ic_rn_local_env = new_rn_env, 
205                                ic_type_env     = new_type_env }
206     return (hsc_env {hsc_IC = new_ic }, name)
207
208 --    Create new uniques and give them sequentially numbered names
209 --    newGrimName :: Session -> String -> IO Name
210 newGrimName cms userName  = do
211     us <- mkSplitUniqSupply 'b'
212     let unique  = uniqFromSupply us
213         occname = mkOccName varName userName
214         name    = mkInternalName unique occname noSrcLoc
215     return name
216
217 ----------------------------------------------------------------------------
218 -- | Replace all the tyvars in a Term with the opaque type GHC.Base.Unknown
219 ----------------------------------------------------------------------------
220 instantiateTyVarsToUnknown :: Session -> Type -> IO Type
221 instantiateTyVarsToUnknown cms ty
222 -- We have a GADT, so just fix its tyvars
223     | Just (tycon, args) <- splitTyConApp_maybe ty
224     , tycon /= funTyCon
225     , isGADT tycon
226     = mapM fixTyVars args >>= return . mkTyConApp tycon
227 -- We have a regular TyCon, so map recursively to its args
228     | Just (tycon, args) <- splitTyConApp_maybe ty
229     , tycon /= funTyCon
230     = do unknownTyVar <- unknownTV
231          args' <- mapM (instantiateTyVarsToUnknown cms) args
232          return$ mkTyConApp tycon args'
233 -- we have a tyvar of kind *
234     | Just tyvar <- getTyVar_maybe ty
235     , ([],_) <- splitKindFunTys (tyVarKind tyvar) 
236     = unknownTV
237 -- we have a higher kind tyvar, so insert an unknown of the appropriate kind
238     | Just tyvar <- getTyVar_maybe ty
239     , (args,_) <- splitKindFunTys (tyVarKind tyvar)
240     = liftM mkTyConTy $ unknownTC !! length args
241 -- Base case
242     | otherwise    = return ty 
243
244  where unknownTV = do 
245          Just (ATyCon unknown_tc) <- lookupName cms unknownTyConName
246          return$ mkTyConTy unknown_tc
247        unknownTC = [undefined, unknownTC1, unknownTC2, unknownTC3]
248        unknownTC1 = do 
249          Just (ATyCon unknown_tc) <- lookupName cms unknown1TyConName
250          return unknown_tc
251        unknownTC2 = do 
252          Just (ATyCon unknown_tc) <- lookupName cms unknown2TyConName
253          return unknown_tc
254        unknownTC3 = do 
255          Just (ATyCon unknown_tc) <- lookupName cms unknown3TyConName
256          return unknown_tc
257 --       isGADT ty | pprTrace' "isGADT" (ppr ty <> colon <> ppr(isGadtSyntaxTyCon ty)) False = undefined
258        isGADT tc | Just dcs <- tyConDataCons_maybe tc = any (not . null . dataConEqSpec) dcs
259                  | otherwise = False
260        fixTyVars ty 
261            | Just (tycon, args) <- splitTyConApp_maybe ty
262            = mapM fixTyVars args >>= return . mkTyConApp tycon
263 -- Fix the tyvar so that the interactive environment doesn't choke on it TODO 
264            | Just tv <- getTyVar_maybe ty = return ty --TODO
265            | otherwise = return ty
266
267 -- | 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
268 stripUnknowns :: [Name] -> Id -> Id
269 stripUnknowns names id = setIdType id . fst . go names . idType 
270                            $ id
271  where 
272    go tyvarsNames@(v:vv) ty 
273     | Just (ty1,ty2) <- splitFunTy_maybe ty = let
274                (ty1',vv') = go tyvarsNames ty1
275                (ty2',vv'')= go vv' ty2
276                in (mkFunTy ty1' ty2', vv'')
277     | Just (ty1,ty2) <- splitAppTy_maybe ty = let
278                (ty1',vv') = go tyvarsNames ty1
279                (ty2',vv'')= go vv' ty2
280                in (mkAppTy ty1' ty2', vv'')
281     | Just (tycon, args) <- splitTyConApp_maybe ty 
282     , Just (tycon', vv') <- (fixTycon tycon tyvarsNames)
283     , (args',vv'') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg 
284                                              in (arg':aa,vv'))
285                             ([],vv') args
286     = (mkAppTys tycon' args',vv'')
287     | Just (tycon, args) <- splitTyConApp_maybe ty
288     , (args',vv') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg 
289                                             in (arg':aa,vv'))
290                            ([],tyvarsNames) args
291     = (mkTyConApp tycon args',vv')
292     | otherwise = (ty, tyvarsNames)
293     where  fixTycon tycon (v:vv) = do
294                k <- lookup (tyConName tycon) kinds
295                return (mkTyVarTy$ mkTyVar v k, vv)
296            kinds = [ (unknownTyConName, liftedTypeKind)
297                    , (unknown1TyConName, kind1)
298                    , (unknown2TyConName, kind2)
299                    , (unknown3TyConName, kind3)]
300            kind1 = mkArrowKind liftedTypeKind liftedTypeKind
301            kind2 = mkArrowKind kind1 liftedTypeKind
302            kind3 = mkArrowKind kind2 liftedTypeKind
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