summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/Stack/CCS.hsc
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/base/GHC/Stack/CCS.hsc')
-rw-r--r--libraries/base/GHC/Stack/CCS.hsc116
1 files changed, 116 insertions, 0 deletions
diff --git a/libraries/base/GHC/Stack/CCS.hsc b/libraries/base/GHC/Stack/CCS.hsc
new file mode 100644
index 0000000000..6d62a1e235
--- /dev/null
+++ b/libraries/base/GHC/Stack/CCS.hsc
@@ -0,0 +1,116 @@
+{-# LANGUAGE Trustworthy #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module : GHC.Stack.CCS
+-- Copyright : (c) The University of Glasgow 2011
+-- License : see libraries/base/LICENSE
+--
+-- Maintainer : cvs-ghc@haskell.org
+-- Stability : internal
+-- Portability : non-portable (GHC Extensions)
+--
+-- Access to GHC's call-stack simulation
+--
+-- @since 4.5.0.0
+-----------------------------------------------------------------------------
+
+{-# LANGUAGE UnboxedTuples, MagicHash, NoImplicitPrelude #-}
+module GHC.Stack.CCS (
+ -- * Call stacks
+ currentCallStack,
+ whoCreated,
+
+ -- * Internals
+ CostCentreStack,
+ CostCentre,
+ getCurrentCCS,
+ getCCSOf,
+ ccsCC,
+ ccsParent,
+ ccLabel,
+ ccModule,
+ ccSrcSpan,
+ ccsToStrings,
+ renderStack
+ ) where
+
+import Foreign
+import Foreign.C
+
+import GHC.Base
+import GHC.Ptr
+import GHC.Foreign as GHC
+import GHC.IO.Encoding
+import GHC.List ( concatMap, reverse )
+
+#define PROFILING
+#include "Rts.h"
+
+data CostCentreStack
+data CostCentre
+
+getCurrentCCS :: dummy -> IO (Ptr CostCentreStack)
+getCurrentCCS dummy = IO $ \s ->
+ case getCurrentCCS## dummy s of
+ (## s', addr ##) -> (## s', Ptr addr ##)
+
+getCCSOf :: a -> IO (Ptr CostCentreStack)
+getCCSOf obj = IO $ \s ->
+ case getCCSOf## obj s of
+ (## s', addr ##) -> (## s', Ptr addr ##)
+
+ccsCC :: Ptr CostCentreStack -> IO (Ptr CostCentre)
+ccsCC p = (# peek CostCentreStack, cc) p
+
+ccsParent :: Ptr CostCentreStack -> IO (Ptr CostCentreStack)
+ccsParent p = (# peek CostCentreStack, prevStack) p
+
+ccLabel :: Ptr CostCentre -> IO CString
+ccLabel p = (# peek CostCentre, label) p
+
+ccModule :: Ptr CostCentre -> IO CString
+ccModule p = (# peek CostCentre, module) p
+
+ccSrcSpan :: Ptr CostCentre -> IO CString
+ccSrcSpan p = (# peek CostCentre, srcloc) p
+
+-- | returns a '[String]' representing the current call stack. This
+-- can be useful for debugging.
+--
+-- The implementation uses the call-stack simulation maintined by the
+-- profiler, so it only works if the program was compiled with @-prof@
+-- and contains suitable SCC annotations (e.g. by using @-fprof-auto@).
+-- Otherwise, the list returned is likely to be empty or
+-- uninformative.
+--
+-- @since 4.5.0.0
+
+currentCallStack :: IO [String]
+currentCallStack = ccsToStrings =<< getCurrentCCS ()
+
+ccsToStrings :: Ptr CostCentreStack -> IO [String]
+ccsToStrings ccs0 = go ccs0 []
+ where
+ go ccs acc
+ | ccs == nullPtr = return acc
+ | otherwise = do
+ cc <- ccsCC ccs
+ lbl <- GHC.peekCString utf8 =<< ccLabel cc
+ mdl <- GHC.peekCString utf8 =<< ccModule cc
+ loc <- GHC.peekCString utf8 =<< ccSrcSpan cc
+ parent <- ccsParent ccs
+ if (mdl == "MAIN" && lbl == "MAIN")
+ then return acc
+ else go parent ((mdl ++ '.':lbl ++ ' ':'(':loc ++ ")") : acc)
+
+-- | Get the stack trace attached to an object.
+--
+-- @since 4.5.0.0
+whoCreated :: a -> IO [String]
+whoCreated obj = do
+ ccs <- getCCSOf obj
+ ccsToStrings ccs
+
+renderStack :: [String] -> String
+renderStack strs = "Stack trace:" ++ concatMap ("\n "++) (reverse strs)