Debugging

The debugging system in ConnectBasic is found principally in the ConnectDebug assembly, it currently has no dependencies on ConnectBasic because I'm hoping that in creating it, we can create some which is useful in either library/source form, to other language implementations running on top of the DLR.

Unlike, say, the ipydbg project, I deliberately wanted something that was going to work with DynamicMethod-based compilation, and also with intepreted programs, as I think interpretation is going to be key to getting the kind of initial-start performance that end-users are going to want.

The way I'm currently going about this is for the language implementation to give its expression tree to an expression tree rewriter which walks the tree and injects callbacks to an implementation of the IInternalDebugger interface - perhaps the simplest way to understand this is to simply read the code, but what follows is a very simple explanation (the implementation as it stands is pretty simple anyway, but seems effective)

The debugging rewriter is provided with an implementation of the IInternalDebugger interface, it then walks the expression tree, specifically looking for method entry/exit, DebugInfo nodes, when the former is encountered, the rewriter injects calls to notification methods on the IInternalDebugger instance. When the latter is encountered, the rewriter injects two main units of code:
  • A callback to ShouldBreak on the IInternalDebugger interface - the implementation uses the information passed to this method to determine whether the program execution has hit a break/stepping point.
  • A command & control loop, if ShouldBreak returns true, the command and control loop is entered, this is an infinite loop which calls back into the IInternalDebugger to find out what it wants to do next, e.g. read/write a variable - when it receives a command, it executes it, and calls back into the debugger with the result. The loop is only exited when the debugger indicates that it is done.

As things stand, there are currently two implementations of IInternalDebugger - ProxyDebugger and SimpleDebugger.
  • ProxyDebugger simply forwards all calls to its methods to another implementation of IInternalDebugger, this allows for code to be instrumented for debugging even when the actual debugger isn't known about ahead of time.
  • SimpleDebugger is (as its name suggests) a simple implementation of a debugger with methods like StepInto, StepOver, etc. It makes use of Events in the System.Threading namespace so that it can be used by a suitable debugging UI, e.g. ConnectShell.

SimpleDebugger implements two interfaces IInternalDebugger (the callback interface used by code that has been instrumented for debugging), and IDebugger which is designed to be a consumer friendly interface, and it is this interface that is used by ConnectShell to avoid a hard dependency on SimpleDebugger.


Last edited Jun 1, 2009 at 8:07 PM by PhilipStears, version 1

Comments

No comments yet.