How to get a stacktrace from SomeException (or any other custom Exception)?

Viewed 98

Is it possible today (GHC 8.8.3+) to extract a stacktrace from an exception that is thrown using throwIO, throwM, etc. I've spend over an hour looking at the docs of Control.Exception and GHC.Stack but couldn't find a function with type SomeException -> CallStack (or similar). I even tried Hoogle, but couldn't find anything.

2 Answers

As @Li-yao Xia said, currently there is no way to do what you want, but there are some workrounds, one of which is add the HasCallStack constraint to your function definition:

import GHC.Stack

head' :: HasCallStack => [a] -> a
head' [] = error "empty list"
head' (x:_) = x

foo :: HasCallStack => [a] -> a
foo xs = head' xs

goo :: HasCallStack => [Int] -> Int
goo (0:_) = error "Divid by zero"
goo xs = div 5 (foo xs)

hoo :: HasCallStack => [Int] -> Int
hoo xs = goo xs + 4

Load the above code into ghci, you can trace a call stack:

ghci> foo []
*** Exception: empty list
CallStack (from HasCallStack):
  error, called at CallStack.hs:4:12 in main:Main
  head', called at CallStack.hs:8:10 in main:Main
  foo, called at <interactive>:14:1 in interactive:Ghci1
ghci> hoo [0, 1]
*** Exception: Divid by zero
CallStack (from HasCallStack):
  error, called at CallStack.hs:11:13 in main:Main
  goo, called at CallStack.hs:15:10 in main:Main
  hoo, called at <interactive>:15:1 in interactive:Ghci1

However, this workaround needs explicit code changes to propagate the stack, which is the drawback.

There are also two other ways:

  • Profiling: ghc -prof -fprof-auto and ghci -fexternal-interpeter -prof
  • DWARF: ghc -g.

For more information, you can see the posts by Simon Marlow, one of the Co-developers of the GHC.

Related