I recently came across an article, Writing a Primitive Debugger. It goes through what a debugger does and the basics of how one functions. I was reminded of a debugger I created for Rhomobile’s Rhodes applications.
There are some key differences between the two. As mentioned in the linked article, a debugger needs a few basic functions to be useful. My goal was to have a useful debugger that could stop at a breakpoint, inspect variables, and execute arbitrary Ruby commands. I had read an article about using GDB to debug Ruby and started initially with that approach. At this point, I really wasn’t writing a debugger but a UI for GDB and Ruby. This worked great when running on the iPhone simulator which runs as a process on the local machine, but did not work on mobile devices or any other platform other than the iPhone simulator.
My approach to this was to work at a little higher level. One interesting feature I had come across in Ruby is set_trace_func. When set, the execution steps of the Ruby VM also trigger your trace function. While this does significantly slow the program down, it allows you to accomplish nearly everything you need to do for a debugger. I adapted this to allow debugging of the application via a TCP connection. I may go into detail later, but you can see the original code that I wrote for this here. It has since been expanded to the full debugger that is being used today, adding complexity and integration with an existing IDE.