Difference between revisions of "GHC/GHCi debugger"

From HaskellWiki
< GHC
Jump to navigation Jump to search
(+cat)
m (→‎Current status: Made the text is more up to date)
(7 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
[[Category:GHC|GHCi debugger]]
 
[[Category:GHC|GHCi debugger]]
The GHCi Debugger project extends ghci with basic debugging capabilities. The GHC 6.7 [http://haskell.org/ghc/dist/current/dist/docs documentation] includes a section on the debugger.
+
The GHCi Debugger project extends ghci with basic debugging capabilities. See the GHC user docs for more info.
   
  +
== Current status ==
This page is a dump of the designs, ideas, and results of the project. Check [http://darcs.haskell.org/SoC/ghc.debugger/demo.mov here] for a Quicktime video demonstrating the use of the debugger.
 
  +
The debugger is available since [http://www.haskell.org/ghc/download_ghc_681.html GHC 6.8.1]. Full documentation in the [http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html user docs].
 
== Current Status ==
 
UPDATE: The debugger is currently available in GHC 6.7 [http://haskell.org/ghc/dist/current/dist nightly builds], so there is no excuse anymore.
 
GHC 6.8 will probably include a debugger, which may or may not be based on this one.
 
 
=== Feature Wise ===
 
* Stack Traces have been dropped and are not being pursued at the moment
 
* The Closure viewer includes support for everything in GHC, but currently GADTs might be problematic
 
* Dynamic breakpoints are fully supported
 
 
== Intermediate Closure Viewer ==
 
The closure viewer is intended to permit working with polymorphic values in breakpoints, as well as to explore intermediate computations without altering the evaluation order.
 
 
This feature is now (more or less) complete. Currently it provides two new commands under ghci, ''':print''' and ''':sprint''', both used in the same way as <tt>:type</tt> or <tt>:info</tt>. The latter prints a semievaluated closure using underscores to represent suspended computations (pretty much as [[Hood]] does). The former one in addition binds these thunks to variable names, so that you can do things with them.
 
 
Example:
 
<pre>
 
Prelude> let li = map Just [1..5]
 
Prelude> length li
 
5
 
Prelude> :sp li
 
li - [_,_,_,_,_,]
 
 
Prelude> head li
 
Just 1
 
 
Prelude> :sp li
 
li - [Just 1,_,_,_,_]
 
 
Prelude> last li
 
Just 5
 
 
Prelude> :sp li
 
li - [Just 1,_,_,_Just 5]
 
 
Prelude> :p li
 
li - [Just 1, (_t1::Maybe Integer),(_t2::Maybe Integer),(_t3::Maybe Integer),Just 5]
 
 
Prelude> _t1 `seq` ()
 
 
Prelude> :p li
 
li - [Just 1, Just 2,(_t3::Maybe Integer),(_t4::Maybe Integer),Just 5]
 
 
Prelude> _t2
 
Just 3
 
</pre>
 
 
Its best feature is that it can work without type information, so you can display polymorphic objects the type of which you don't know. However if there is type information available, it is used. Thanks to this it can work with opaque or coerced types. For instance:
 
 
<haskell>
 
data Opaque = forall a. O a
 
</haskell>
 
 
<pre>
 
*Test2> let li = map Just [1..5]
 
*Test2> let o = O li
 
*Test2> head li `seq` ()
 
*Test2> length li `seq` ()
 
*Test2> :p o
 
o - [O Just 1,(_t1::Integer),(_t2::Integer),(_t3::Integer),(_t4::Integer)]
 
</pre>
 
 
In the example above the <tt>li</tt> inside <tt>o</tt> has an opaque existential type. However, the closure viewer makes it possible to recover its type when it gets evaluated.
 
 
Other currently proposed extensions are a <tt>safeCoerce</tt> function (not so useful, it depends on ghc-api) and an <tt>unsafeDeepSeq</tt> (this one is decoupled from ghc-api). There is also a generally useful (for compiler/tool developers) <tt>isFullyEvaluated</tt> query function. The signatures being:
 
 
<pre>
 
isFullyEvaluated :: a -> IO Bool
 
unsafeDeepSeq :: a -> b -> b
 
safeCoerce :: GHC.Session -> a -> Maybe b
 
</pre>
 
 
Finally, note that there are some inconveniences with the current implementation, such as <tt>:p</tt> binding the same closure to different names when used twice on the same closure, but they are minor and temporary (hopefully).
 
 
== Dynamic Breakpoints ==
 
 
See the user details of the current implementation at the GHC User Guide.
 
 
=== Event sites and events ===
 
We define 'event sites' as points in the code where you can want to set a breakpoint. Current candidates for sites are:
 
* On the entrance to a function / lambda abstraction
 
* <strike>Prior to function applications</strike> ''(this one does not make sense unless it forces the application using <tt>$!</tt>)
 
* Local bindings in lets and wheres
 
* Entrance to statements in monadic-do code
 
 
Overlapping or unnecesary events should be coalesced into a single one.
 
The rationale for what is an event and what is not is trying to find a middle point between the user interests and the overhead introduced:
 
* We want to keep the overhead manageable, thus we want to keep the number of breakpoints low.
 
* The user wants to introduce breakpoints at will.
 
 
Credit goes to both A. Tolmach's ML debugger and the OCaml time-travel debugger for providing the inspiration.
 
 
=== Proposals ===
 
There are currently the following proposals:
 
 
* Instrument the code with a conditional breakpoint at every event site. Sites are numbered, and the condition uses a site-indexed array to check if there is a breakpoint enabled. The array is maintained inside ghci. Hopefully not much magic is required for this one.
 
 
* In the style of the previous one, but no array is maintained. All the breakpoint conditions are set to False, so almost no overhead is incurred. When the user demands a breakpoint, its BCO in the heap is rewritten to enable the breakpoint. Feasibility of this?
 
 
* Don't use instrumentation. Have a new header for BCOs with breakpoints, say BCO_BREAK, and change headers in execution time on user demand (as in the previous proposal). The problem I see with this one is how to extract the local bindings. I don't fully grok the scheme Lemmih uses to do that yet.
 
 
During this project we have explored the first one, under the lemma of ``do the simplest thing that could possibly work``.
 
I'm sure there are many other designs. Please add your proposal or just throw an idea in.
 
 
== Call Traces ==
 
We want to have ''strict'' call traces, not the lazy ones.
 
 
=== Proposals ===
 
 
* It has been suggested that stealing ideas from Cost-Centre Stacks may be useful.
 
 
<strike>
 
* Based on Tolmach's debugger, we can instrument the source code to build a timeline of events (either lazily or not). The events contain a pointer to its lexical parent event. With that it should be possible to extract a call trace:
 
# CASE 1: We are in a Function definition (FN):
 
## Go back one step in the timeline: it necessarily is an application (APP)
 
## Go back to its 'binding', i.e. its lexical parent. Keep doing this until it is a FN, then start again from case 1.
 
## Once you reach the top, i.e. the 0 event, you are done. Display all theAPPs you encountered in the way
 
# CASE 2: We are in a site other than a FN:
 
## Go back [[lexically]] until you hit a FN and continue with case 1.
 
 
This is just a wild, untested idea. It's possible that it would not work. Also even if it worked, it's possible that the overhead was unadmissible.
 
</strike> WON'T WORK WITH LAZINESS
 
 
== Integration ==
 
Allowing other tools to integrate with the debugger is an important goal. It should not be taken lightly though.
 
 
* It has been suggested to create a client/server protocol so that the debugger can be used by other tools.
 
 
* On the other hand, arguably it would be much easier to provide integration to clients of the ghc-api via some form of debugger api.
 
 
* Finally, it should be possible to derive the client/server architecture as an afterthought provided there is a debugger api in the ghc-api.
 
 
== Further pointers ==
 
 
# [http://www.tekno.chalmers.se/~murk/rectus Rectus], '' Oleg M&uuml;rk and Lennart Kolmodin''
 
# [http://caml.inria.fr/pub/docs/manual-ocaml/manual030.html The Ocaml Debugger], ''The OCaml Team''
 
# [http://web.cecs.pdx.edu/~apt/jfp95.ps A debugger for Standard ML], ''A.Tolmach, A. Appel''
 
# [http://www.haskell.org//pipermail/cvs-ghc/2006-April/029040.html The original discussion in the ghc-cvs mailing list]
 
 
== How to get the patches ==
 
 
The patches are available at the SoC ghc.debugger [http://darcs.haskell.org/SoC/ghc.debugger/ darcs repo]:
 
<pre>
 
darcs get --partial http://darcs.haskell.org/SoC/ghc.debugger
 
</pre>
 
This is a modified version of GHC 6.6. Build it following the instructions at the [http://hackage.haskell.org/trac/ghc GHC developers wiki].
 
 
If darcs-all does not do it for you, you will need to manually pull a few patches at the libraries/base repo, to be pulled from http://darcs.haskell.org/SoC/ghc.debugger/libraries/base
 
 
Have fun! (and feel free to spam [mailto:mnislaih@gmail.com me] with bugs, suggestions or requests!)
 

Revision as of 21:29, 16 December 2012

The GHCi Debugger project extends ghci with basic debugging capabilities. See the GHC user docs for more info.

Current status

The debugger is available since GHC 6.8.1. Full documentation in the user docs.