Since I’m guessing most of my readers have never build a debugger before
(I certainly hadn’t), let’s start with the debugger equivalent of Hello,
World!
import clr
clr.AddReference('CorDebug')
import sys
from System.Reflection import Assembly
from System.Threading import AutoResetEvent
from Microsoft.Samples.Debugging.CorDebug import CorDebugger
ipy = Assembly.GetEntryAssembly().Location
py_file = sys.argv[1]
cmd_line = ""%s" -D "%s"" % (ipy, py_file)
evt = AutoResetEvent(False)
def OnCreateAppDomain(s,e):
print "OnCreateAppDomain", e.AppDomain.Name
e.AppDomain.Attach()
def OnProcessExit(s,e):
print "OnProcessExit"
evt.Set()
debugger = CorDebugger(CorDebugger.GetDefaultDebuggerVersion())
process = debugger.CreateProcess(ipy, cmd_line)
process.OnCreateAppDomain += OnCreateAppDomain
process.OnProcessExit += OnProcessExit
process.Continue(False)
evt.WaitOne()
I start by adding a reference to the CorDebug library I discussed at the
end of my last
post
(that’s the low level managed debugger API plus the C# definitions of
the various COM APIs). Then I need both the path to the IPy executable
as well as the script to be run, which is passed in on the command line
(sys.argv). For now, I just use Reflection to find the path to the
current ipy.exe and use that. I use those to build a command line –
you’ll notice I’m adding the –D on the command line to generate debugger
symbols.
Next, I define two event handlers: OnCreateAppDomain and OnProcessExit.
When the AppDomain is created, the debugger needs to explicitly attach
to it. When the process exits, we signal an AutoResetEvent to indicate
our program can exit.
Then it’s a simple process of creating the CorDebugger object, creating
a process, setting up the process event handlers and then running the
process via the call to Continue. We then wait on the AutoResetEvent for
the debugged process to exit. And voila, you have the worlds simplest
debugger in about 30 lines of code.
To run it, you run the ipy.exe interpreter and pass in the ipydbg script
above and the python script to be debugged. You also have to pass –X:MTA
on the command line, as the ICorDebug objects only work from a
multi-threaded apartment. When you run it, you get something that looks
like this:
» ipy -X:MTA ipydbg.py simpletest.py
OnCreateAppDomain DefaultDomain
35
OnProcessExit
Simpletest.py is a very simple script that prints the results of adding
two numbers together. Here, you see the event handlers fire by writing
text out to the console.
For those of you who’d like to see this code actually run on your
machine, I’ve created an ipydbg project up on
GitHub. The tree version
that goes with this blog post is
here.
If you’re not running Git, you can download a tar
or zip of the project via the “download” button at the top of the page.
It includes both the CorDebug source as well as the ipydbg.py file
(shown above) and the simpletest.py file. It also has a compiled version
of CorDebug.dll, so you don’t have to compile it yourself (for those IPy
only coders who don’t have VS on their machine).