Added the new :breakpoint continue option
[ghc.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 sigmaType ty = mkForAllTys (varSetElems$ tyVarsOfType (dropForAlls ty)) ty
264 go tyvarsNames@(v:vv) ty
265 | Just (ty1,ty2) <- splitFunTy_maybe ty = let
266 (ty1',vv') = go tyvarsNames ty1
267 (ty2',vv'')= go vv' ty2
268 in (mkFunTy ty1' ty2', vv'')
269 | Just (ty1,ty2) <- splitAppTy_maybe ty = let
270 (ty1',vv') = go tyvarsNames ty1
271 (ty2',vv'')= go vv' ty2
272 in (mkAppTy ty1' ty2', vv'')
273 | Just (tycon, args) <- splitTyConApp_maybe ty
274 , Just (tycon', vv') <- (fixTycon tycon tyvarsNames)
275 , (args',vv'') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg
276 in (arg':aa,vv'))
277 ([],vv') args
278 = (mkAppTys tycon' args',vv'')
279 | Just (tycon, args) <- splitTyConApp_maybe ty
280 , (args',vv') <- foldr (\arg (aa,vv) -> let (arg',vv') = go vv' arg
281 in (arg':aa,vv'))
282 ([],tyvarsNames) args
283 = (mkTyConApp tycon args',vv')
284 | otherwise = (ty, tyvarsNames)
285 where fixTycon tycon (v:vv) = do
286 k <- lookup (tyConName tycon) kinds
287 return (mkTyVarTy$ mkTyVar v k, vv)
288 kinds = [ (unknownTyConName, liftedTypeKind)
289 , (unknown1TyConName, kind1)
290 , (unknown2TyConName, kind2)
291 , (unknown3TyConName, kind3)]
292 kind1 = mkArrowKind liftedTypeKind liftedTypeKind
293 kind2 = mkArrowKind kind1 liftedTypeKind
294 kind3 = mkArrowKind kind2 liftedTypeKind
295 stripUnknowns _ id = id
296
297 -----------------------------
298 -- | The :breakpoint command
299 -----------------------------
300 bkptOptions :: String -> GHCi Bool
301 bkptOptions "continue" = -- We want to quit if in an inferior session
302 liftM not isTopLevel
303 bkptOptions "stop" = do
304 inside_break <- liftM not isTopLevel
305 when inside_break $ throwDyn StopChildSession
306 return False
307
308 bkptOptions cmd = do
309 dflags <- getDynFlags
310 bt <- getBkptTable
311 bkptOptions' (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' ("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 sess <- getSession
337 dflags <- getDynFlags
338 mod <- io$ GHC.findModule sess (GHC.mkModuleName mod_name) Nothing
339 ghciHandleDyn (handleBkptEx mod) $
340 case f mod bt of
341 (newTable, site) -> do
342 setBkptTable newTable
343 io (putStrLn ("Breakpoint set at " ++
344 show (getSiteCoords newTable mod site)))
345
346 bkptOptions' ("del":cmds) bt
347 | [i'] <- cmds
348 , [(i,[])] <- reads i'
349 , bkpts <- btList bt
350 = if i > length bkpts
351 then throwDyn $ CmdLineError
352 "Not a valid breakpoint #. Use :breakpoint list to see the current breakpoints."
353 else
354 let (mod, site) = bkpts !! (i-1)
355 in handleDel mod $ delBkptBySite mod site
356
357 | [fn,line] <- cmds
358 , [(lineNum,[])] <- reads line
359 , mod <- GHC.mkModule mainPackageId (GHC.mkModuleName fn)
360 = handleDel mod $ delBkptByLine mod lineNum
361
362 | [fn,line,col] <- cmds
363 , [(lineNum,[])] <- reads line
364 , [(colNum,[])] <- reads col
365 , mod <- GHC.mkModule mainPackageId (GHC.mkModuleName fn)
366 = handleDel mod $ delBkptByCoord mod (lineNum, colNum)
367
368 | otherwise = throwDyn $ CmdLineError $
369 "syntax: :breakpoint del (breakpoint # | Module line [col])"
370
371 where delMsg = "Breakpoint deleted"
372 handleDel mod f = ghciHandleDyn (handleBkptEx mod) $ do
373 modifyBkptTable f
374 newTable <- getBkptTable
375 sess <- getSession
376 dflags <- getDynFlags
377 io$ putStrLn delMsg
378
379 bkptOptions' _ _ = throwDyn $ CmdLineError $
380 "syntax: :breakpoint (list|continue|stop|add|del)"
381
382 -- Error messages
383 handleBkptEx :: Module -> Debugger.BkptException -> a
384 handleBkptEx _ NoBkptFound = error "No suitable breakpoint site found"
385 -- ^ TODO Instead of complaining, set a bkpt in the next suitable line
386 handleBkptEx _ NotNeeded = error "Nothing to do"
387 handleBkptEx m NotHandled = error$ "Module " ++ showSDoc (ppr m) ++ " was not loaded under debugging mode. Enable debugging mode with -fdebugging (and reload your module)"
388
389 -------------------------
390 -- Breakpoint Tables
391 -------------------------
392
393 data BkptTable a = BkptTable {
394 -- | An array of breaks, indexed by site number
395 breakpoints :: Map.Map a (UArray Int Bool)
396 -- | A list of lines, each line can have zero or more sites, which are annotated with a column number
397 , sites :: Map.Map a [[(SiteNumber, Int)]]
398 }
399
400 sitesOf :: Ord a => BkptTable a -> a -> Maybe [[(SiteNumber, Int)]]
401 sitesOf bt fn = Map.lookup fn (sites bt)
402 bkptsOf bt fn = Map.lookup fn (breakpoints bt)
403
404
405 -- The functions for manipulating BkptTables do throw exceptions
406 data BkptException =
407 NotHandled
408 | NoBkptFound
409 | NotNeeded -- Used when a breakpoint was already enabled
410 deriving Typeable
411
412 emptyBkptTable :: Ord a => BkptTable a
413 addModule :: Ord a => a -> [(SiteNumber,Coord)] -> BkptTable a -> BkptTable a
414 -- | Lines start at index 1
415 addBkptByLine :: Ord a => a -> Int -> BkptTable a -> (BkptTable a, SiteNumber)
416 addBkptByCoord :: Ord a => a -> Coord -> BkptTable a -> (BkptTable a, SiteNumber)
417 delBkptByLine :: Ord a => a -> Int -> BkptTable a -> BkptTable a
418 delBkptBySite :: Ord a => a -> SiteNumber -> BkptTable a -> BkptTable a
419 delBkptByCoord :: Ord a => a -> Coord -> BkptTable a -> BkptTable a
420
421 isBkptEnabled :: Ord a => BkptTable a -> BkptLocation a -> Bool
422 btElems :: Ord a => BkptTable a -> [(a, [SiteNumber])]
423 btList :: Ord a => BkptTable a -> [BkptLocation a]
424 sitesList :: Ord a => BkptTable a -> [(a, [Coord])]
425 getSiteCoords :: Ord a => BkptTable a -> a -> SiteNumber -> Coord
426
427 emptyBkptTable = BkptTable Map.empty Map.empty
428
429 addBkptByLine a i bt
430 | Just lines <- sitesOf bt a
431 , Just bkptsArr <- bkptsOf bt a
432 , i < length lines
433 = case lines!!i of
434 [] -> throwDyn NoBkptFound
435 (x:_) -> let (siteNum,col) = x
436 wasAlreadyOn = bkptsArr ! siteNum
437 newArr = bkptsArr // [(siteNum, True)]
438 newTable = Map.insert a newArr (breakpoints bt)
439 in if wasAlreadyOn
440 then throwDyn NotNeeded
441 else (bt{breakpoints=newTable}, siteNum)
442
443 | Just sites <- sitesOf bt a
444 = throwDyn NoBkptFound
445 | otherwise = throwDyn NotHandled
446
447 addBkptByCoord a (r,c) bt
448 | Just lines <- sitesOf bt a
449 , Just bkptsArr <- bkptsOf bt a
450 , r < length lines
451 = case [ (sn,col) | (sn,col)<-lines!!r, col>=c] of
452 [] -> throwDyn NoBkptFound
453 (x:_) -> let (siteNum, col) = x
454 wasAlreadyOn = bkptsArr ! siteNum
455 newArr = bkptsArr // [(siteNum, True)]
456 newTable = Map.insert a newArr (breakpoints bt)
457 in if wasAlreadyOn
458 then throwDyn NotNeeded
459 else (bt{breakpoints=newTable}, siteNum)
460
461 | Just sites <- sitesOf bt a
462 = throwDyn NoBkptFound
463 | otherwise = throwDyn NotHandled
464
465 delBkptBySite a i bt
466 | Just bkptsArr <- bkptsOf bt a
467 , not (inRange (bounds bkptsArr) i)
468 = throwDyn NoBkptFound
469
470 | Just bkptsArr <- bkptsOf bt a
471 , bkptsArr ! i -- Check that there was a enabled bkpt here
472 , newArr <- bkptsArr // [(i,False)]
473 , newTable <- Map.insert a newArr (breakpoints bt)
474 = bt {breakpoints=newTable}
475
476 | Just sites <- sitesOf bt a
477 = throwDyn NotNeeded
478
479 | otherwise = throwDyn NotHandled
480
481 delBkptByLine a l bt
482 | Just sites <- sitesOf bt a
483 , (site:_) <- [s | (s,c') <- sites !! l]
484 = delBkptBySite a site bt
485
486 | Just sites <- sitesOf bt a
487 = throwDyn NoBkptFound
488
489 | otherwise = throwDyn NotHandled
490
491 delBkptByCoord a (r,c) bt
492 | Just sites <- sitesOf bt a
493 , (site:_) <- [s | (s,c') <- sites !! r, c>=c', isBkptEnabled bt (a,s)]
494 = delBkptBySite a site bt
495
496 | Just sites <- sitesOf bt a
497 = throwDyn NoBkptFound
498
499 | otherwise = throwDyn NotHandled
500
501 btElems bt = [ (a, [i | (i,True) <- assocs siteArr])
502 | (a, siteArr) <- Map.assocs (breakpoints bt) ]
503
504 btList bt = [(a,site) | (a, sites) <- btElems bt, site <- sites]
505
506 sitesList bt = [ (a, sitesCoords sitesCols) | (a, sitesCols) <- Map.assocs (sites bt) ]
507 where sitesCoords sitesCols =
508 [ (row,col)
509 | (row, cols) <- zip [0..] sitesCols, (_,col) <- cols ]
510
511 getSiteCoords bt a site
512 | Just rows <- sitesOf bt a
513 = head [ (r,c) | (r,row) <- zip [0..] rows
514 , (s,c) <- row
515 , s == site ]
516
517 -- addModule is dumb and inefficient, but it does the job
518 addModule a [] bt = bt {sites = Map.insert a [] (sites bt)}
519 addModule a siteCoords bt
520 | nrows <- maximum$ [i | (_,(i,j)) <- siteCoords ]
521 , sitesByRow <- [ [(s,c) | (s,(r,c)) <- siteCoords, r==i]
522 | i <- [0..nrows] ]
523 , nsites <- length siteCoords
524 , initialBkpts <- listArray (1, nsites) (repeat False)
525 = bt{ sites = Map.insert a sitesByRow (sites bt)
526 , breakpoints = Map.insert a initialBkpts (breakpoints bt) }
527
528 isBkptEnabled bt (a,site)
529 | Just bkpts <- bkptsOf bt a
530 , inRange (bounds bkpts) site
531 = bkpts ! site
532 | otherwise = panic "unexpected condition: I don't know that breakpoint site"
533
534 -----------------
535 -- Other stuff
536 -----------------
537 refreshBkptTable :: [ModSummary] -> GHCi ()
538 refreshBkptTable [] = return ()
539 refreshBkptTable (ms:mod_sums) = do
540 sess <- getSession
541 when isDebugging $ do
542 old_table <- getBkptTable
543 new_table <- addModuleGHC sess old_table (GHC.ms_mod ms)
544 setBkptTable new_table
545 refreshBkptTable mod_sums
546 where addModuleGHC sess bt mod = do
547 Just mod_info <- io$ GHC.getModuleInfo sess mod
548 dflags <- getDynFlags
549 let sites = GHC.modInfoBkptSites mod_info
550 io$ debugTraceMsg dflags 2
551 (ppr mod <> text ": inserted " <> int (length sites) <>
552 text " breakpoints")
553 return$ addModule mod sites bt
554 #if defined(GHCI) && defined(DEBUGGER)
555 isDebugging = Opt_Debugging `elem` flags (GHC.ms_hspp_opts ms)
556 #else
557 isDebugging = False
558 #endif