From 6be09e884730f19da6c24fc565980f515300e53c Mon Sep 17 00:00:00 2001 From: Simon Marlow Date: Thu, 7 Jan 2016 11:36:41 +0000 Subject: Enable stack traces with ghci -fexternal-interpreter -prof Summary: The main goal here is enable stack traces in GHCi. After this change, if you start GHCi like this: ghci -fexternal-interpreter -prof (which requires packages to be built for profiling, but not GHC itself) then the interpreter manages cost-centre stacks during execution and can produce a stack trace on request. Call locations are available for all interpreted code, and any compiled code that was built with the `-fprof-auto` familiy of flags. There are a couple of ways to get a stack trace: * `error`/`undefined` automatically get one attached * `Debug.Trace.traceStack` can be used anywhere, and prints the current stack Because the interpreter is running in a separate process, only the interpreted code is running in profiled mode and the compiler itself isn't slowed down by profiling. The GHCi debugger still doesn't work with -fexternal-interpreter, although this patch gets it a step closer. Most of the functionality of breakpoints is implemented, but the runtime value introspection is still not supported. Along the way I also did some refactoring and added type arguments to the various remote pointer types in `GHCi.RemotePtr`, so there's better type safety and documentation in the bridge code between GHC and ghc-iserv. Test Plan: validate Reviewers: bgamari, ezyang, austin, hvr, goldfire, erikd Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1747 GHC Trac Issues: #11047, #11100 --- ghc/GHCi/UI.hs | 52 ++++++++++++++++++++++++---------------------------- ghc/GHCi/UI/Monad.hs | 2 +- 2 files changed, 25 insertions(+), 29 deletions(-) (limited to 'ghc') diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs index 4fcbe6d7fe..7bd9bbeb77 100644 --- a/ghc/GHCi/UI.hs +++ b/ghc/GHCi/UI.hs @@ -39,6 +39,8 @@ import Debugger -- The GHC interface import GHCi +import GHCi.RemoteTypes +import GHCi.BreakArray import DynFlags import ErrUtils import GhcMonad ( modifySession ) @@ -58,7 +60,6 @@ import PrelNames import RdrName ( RdrName, getGRE_NameQualifier_maybes, getRdrName ) import SrcLoc import qualified Lexer -import ByteCodeTypes (BreakInfo(..)) import StringBuffer import Outputable hiding ( printForUser, printForUserPartWay, bold ) @@ -2651,7 +2652,7 @@ pprStopped res = <> text (GHC.resumeDecl res)) <> char ',' <+> ppr (GHC.resumeSpan res) where - mb_mod_name = moduleName <$> breakInfo_module <$> GHC.resumeBreakInfo res + mb_mod_name = moduleName <$> GHC.breakInfo_module <$> GHC.resumeBreakInfo res showPackages :: GHCi () showPackages = do @@ -3094,24 +3095,19 @@ findBreakAndSet md lookupTickTree = do some -> mapM_ (breakAt breakArray) some where breakAt breakArray (tick, pan) = do - success <- liftIO $ setBreakFlag True breakArray tick - if success - then do - (alreadySet, nm) <- - recordBreak $ BreakLocation - { breakModule = md - , breakLoc = RealSrcSpan pan - , breakTick = tick - , onBreakCmd = "" - } - printForUser $ - text "Breakpoint " <> ppr nm <> - if alreadySet - then text " was already set at " <> ppr pan - else text " activated at " <> ppr pan - else do - printForUser $ text "Breakpoint could not be activated at" - <+> ppr pan + setBreakFlag True breakArray tick + (alreadySet, nm) <- + recordBreak $ BreakLocation + { breakModule = md + , breakLoc = RealSrcSpan pan + , breakTick = tick + , onBreakCmd = "" + } + printForUser $ + text "Breakpoint " <> ppr nm <> + if alreadySet + then text " was already set at " <> ppr pan + else text " activated at " <> ppr pan -- When a line number is specified, the current policy for choosing -- the best breakpoint is this: @@ -3390,12 +3386,13 @@ deleteBreak identity = do mapM_ (turnOffBreak.snd) this setGHCiState $ st { breaks = rest } -turnOffBreak :: BreakLocation -> GHCi Bool +turnOffBreak :: BreakLocation -> GHCi () turnOffBreak loc = do (arr, _) <- getModBreak (breakModule loc) - liftIO $ setBreakFlag False arr (breakTick loc) + hsc_env <- GHC.getSession + liftIO $ enableBreakpoint hsc_env arr (breakTick loc) False -getModBreak :: Module -> GHCi (GHC.BreakArray, Array Int SrcSpan) +getModBreak :: Module -> GHCi (ForeignRef BreakArray, Array Int SrcSpan) getModBreak m = do Just mod_info <- GHC.getModuleInfo m let modBreaks = GHC.modInfoModBreaks mod_info @@ -3403,11 +3400,10 @@ getModBreak m = do let ticks = GHC.modBreaks_locs modBreaks return (arr, ticks) -setBreakFlag :: Bool -> GHC.BreakArray -> Int -> IO Bool -setBreakFlag toggle arr i - | toggle = GHC.setBreakOn arr i - | otherwise = GHC.setBreakOff arr i - +setBreakFlag :: Bool -> ForeignRef BreakArray -> Int -> GHCi () +setBreakFlag toggle arr i = do + hsc_env <- GHC.getSession + liftIO $ enableBreakpoint hsc_env arr i toggle -- --------------------------------------------------------------------------- -- User code exception handling diff --git a/ghc/GHCi/UI/Monad.hs b/ghc/GHCi/UI/Monad.hs index 2a2372d5f9..87b6d27c5d 100644 --- a/ghc/GHCi/UI/Monad.hs +++ b/ghc/GHCi/UI/Monad.hs @@ -118,7 +118,7 @@ data GHCiState = GHCiState noBuffering :: ForeignHValue } -type TickArray = Array Int [(BreakIndex,RealSrcSpan)] +type TickArray = Array Int [(GHC.BreakIndex,RealSrcSpan)] -- | A GHCi command data Command -- cgit v1.2.1