Indeed I hope to publish a blog post about this feature soon. I was hoping to have it ready for the release but unfortunately time has been very tight recently.
In short:
-
HasCallStackBacktrace
requires that all functions of interest in the failing branch of the call-graph have a HasCallStack
constraint. Unfortunately, it does look like something isnāt quite right in the behavior here. Iāve opened #24807 to track this (and have now fixed it)
-
CostCentreBacktrace
requires not only -prof
but also that cost-centres are added to the program (e.g. via a {-# CCS ... #-}
pragma or -fprof-auto
-
ExecutionBacktrace
requires DWARF support and that all libraries of your program (e.g. including base
) are built with -g
. As we see here, if any function in the call-chain does not have debug information the backtrace will be truncated at that frame.
-
IPEBacktrace
requires -finfo-prov-map
. In general the more packages that are built with IPE information, the more helpful this backtrace will be. However, unlike ExecutionBacktrace
, absence of IPE information for a frame will not truncate the backtrace but rather will simply contribute no useful information.
With a GHC build with IPE and debug information enabled (and the fix noted above), I get the following output from your program:
$ _build-ipe/stage1/bin/ghc hi.hs -g3 -finfo-table-map -prof -fprof-auto -fforce-recomp
$ ./hi h
hi: Some Pesky Error
CallStack (from HasCallStack):
error, called at hi.hs:8:9 in main:Main
f, called at hi.hs:13:32 in main:Main
CallStack (from -prof):
Main.f (hi.hs:(8,1)-(9,24))
Main.g (hi.hs:13:1-35)
Main.main.\ (hi.hs:21:3-18)
Main.main (hi.hs:(15,1)-(21,18))
Cost-centre stack backtrace:
Main.main (hi.hs:(15,1)-(21,18))
Main.main.\ (hi.hs:21:3-18)
Main.g (hi.hs:13:1-35)
Main.f (hi.hs:(8,1)-(9,24))
Native stack backtrace:
set_initial_registers (rts/Libdw.c:294.5) in /mnt/data/exp/ghc/ghc-9.10/hi
dwfl_thread_getframes in
get_one_thread_cb in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
dwfl_getthreads in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
dwfl_getthread_frames in /nix/store/53nia34f1pqf89idqs4bbm86k0xfgydf-elfutils-0.189/lib/libdw-0.189.so
libdwGetBacktrace (rts/Libdw.c:263.15) in /mnt/data/exp/ghc/ghc-9.10/hi
_ghczminternal_GHCziInternalziExecutionStackziInternal_sat_s2QY_entry (libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc:217.31) in /mnt/data/exp/ghc/ghc-9.10/hi
stg_keepAlive_frame_info (rts/PrimOps.cmm:2954.1) in /mnt/data/exp/ghc/ghc-9.10/hi
ghczminternal_GHCziInternalziExecutionStackziInternal_collectStackTrace1_info (libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc:86.10) in /mnt/data/exp/ghc/ghc-9.10/hi
ghczminternal_GHCziInternalziExceptionziBacktrace_zdwcollectBacktraces_info (libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs:145.54) in /mnt/data/exp/ghc/ghc-9.10/hi
ghczminternal_GHCziInternalziExceptionziBacktrace_collectBacktraces1_info (libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs:43.9) in /mnt/data/exp/ghc/ghc-9.10/hi
ghczminternal_GHCziInternalziException_errorCallWithCallStackException_info (libraries/ghc-internal/src/GHC/Internal/Exception.hs:122.1) in /mnt/data/exp/ghc/ghc-9.10/hi
stg_marked_upd_frame_info (rts/Updates.cmm:56.1) in /mnt/data/exp/ghc/ghc-9.10/hi
_ghczminternal_GHCziInternalziTopHandler_realzuhandler_r387_entry (libraries/ghc-internal/src/GHC/Internal/TopHandler.hs:188.1) in /mnt/data/exp/ghc/ghc-9.10/hi
stg_catch_frame_info (rts/Exception.cmm:405.1) in /mnt/data/exp/ghc/ghc-9.10/hi
stg_unmaskAsyncExceptionszh_ret_info (rts/Exception.cmm:87.1) in /mnt/data/exp/ghc/ghc-9.10/hi
stg_stop_thread_info (rts/StgStartup.cmm:47.1) in /mnt/data/exp/ghc/ghc-9.10/hi
StgRunIsImplementedInAssembler (rts/StgCRun.c:378.5) in /mnt/data/exp/ghc/ghc-9.10/hi
schedule (rts/Schedule.c:481.13) in /mnt/data/exp/ghc/ghc-9.10/hi
scheduleWaitThread (rts/Schedule.c:2675.11) in /mnt/data/exp/ghc/ghc-9.10/hi
rts_evalLazyIO (rts/RtsAPI.c:565.1) in /mnt/data/exp/ghc/ghc-9.10/hi
hs_main (rts/RtsMain.c:73.18) in /mnt/data/exp/ghc/ghc-9.10/hi
in /mnt/data/exp/ghc/ghc-9.10/hi
__libc_start_call_main in
__libc_start_main@@GLIBC_2.34 in /nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib/libc.so.6
_start in /mnt/data/exp/ghc/ghc-9.10/hi
IPE backtrace:
Cmm$rts/StgStartup.cmm. (:)
Cmm$rts/Exception.cmm. (:)
Cmm$rts/Exception.cmm. (:)
GHC.Internal.TopHandler. (:)
Cmm$rts/Updates.cmm. (:)
GHC.Internal.Exception.bindIO (libraries/ghc-internal/src/GHC/Internal/Base.hs:2246:1-76)
GHC.Internal.Exception.Backtrace. (:)
GHC.Internal.Exception.Backtrace.$ (libraries/ghc-internal/src/GHC/Internal/Base.hs:2180:1-9)
HasCallStack backtrace:
collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:92:13 in ghc-internal:GHC.Internal.Exception
toExceptionWithBacktrace, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:127:5 in ghc-internal:GHC.Internal.Exception
error, called at hi.hs:8:9 in main:Main
f, called at hi.hs:13:32 in main:Main
In this case, the trivial nature of the test program means that the execution backtraces arenāt particularly helpful. It may be that IPE coverage needs improvement in this case or that we should improve the stack decoderās treatment of primitive stack frame types (e.g. update frames, see #24811, #24812). I havenāt looked closely enough at this program to see why that is but I donāt doubt that there are improvements that could be made here.
An aside: When interpreting IPE and DWARF ābacktracesā one must remember that the execution stack tracks continuations and not call-sites. In contrast to C, where there is a very strong correspondence between continuations and call-sites, in Haskell tail calls are quite common and therefore you will often see the entries from the āfutureā of your program in the backtrace.