In Part I we took a quick tour of Windows Services. We ended our discussion with the difficultly of debugging Services. In Part II we will see how we can create a refined way of debugging Services in a systematic and usable fashion.
A very cleaver technique for debugging services with UM debuggers by means of attaching a debugger to them is done by trying to delay the Service until a debugger is run and attached to it. A simple method would be to use Sleep(). This function would block the execution of the thread in question until the timeout expires. We may set our Service to Sleep for say 10 seconds, which should be enough for us to hook our debugger to it. To attach a debugger to a running process one needs to browse the list of running applications, find the process in question and attach the debugger to it. This is tedious, error prone (select another process and you have to start over, remember the sleep will most certainly timeout by then) and, after repeating a few time, boring. Consider also that you may have multiple instances of your application/Service running, so you need to distinguish the one you’re interested in from a list of identical image names. Not fun. But, there is a better way.
What if we find a way for the Service to hook itself to a debugger? Sounds tricky, but it’s doable, in a way. Remember that a program that issues an unhandled exception will get terminated by the OS. Windows displays an infamous message stating that the application in question has thrown the towel in, and asks the user whether they want to close the application or debug it. Now clicking that Debug button will get us to the debugger, automating along the way everything involved in attaching an application to a debugger including running the debugger itself! Great, but how can we generate an unhandled exception? How do we know whether a real exception occurred in our process or it’s the one we generated? Granted, in both cases you’d want to hook a debugger and investigate anyway, but if you know it’s your artificial exception then you wouldn’t need to do investigative work every time you employ this method even if out of sheer paranoia.
An interesting solution to this problem is to actually issue a breakpoint exception. As it turns out breakpoints are a special form of exceptions that debuggers catch and handle. If we use the same method we’d have accomplished many design goals in one go. For a start the exception is quite clearly not an application error and we don’t need to investigate it any further. Besides that, it’s an exception clearly dedicated to debugging, so it does document the fact that we are trying to debug the application and not just crash it. Finally, and perhaps most importantly, any debugger already attached to the application (including KM debuggers) will break where we throw the exception precisely because it’s a breakpoint exception (it won’t differentiate if it had inserted that breakpoint because the user had previously requested it or the application generated it). In other words, we’d get ourselves a nice permanent breakpoint. And here is a very important point to remember: never forget to remove such debugging techniques from your final production code!
So how do you do it?
Simple, really. In the code, wherever we want a debugger to be present, before that code section we simply add a line of assembly to raise interrupt 3.
In Intel Assembly Syntax:
__asm int 3
In GCC Assembly Syntax:
That’s it. On that particular line of code you’d get an unhandled exception (assuming your Service doesn’t explicitly or implicitly handle breakpoint exceptions) and you’ll see the dreaded crash dialog. Simply choose to debug the application in question and select a debugger that is either running or a new instance.
Practical Service Debugging Workflow
With Visual Studio, I tend to have a session with the project in question open, Debug Configuration selected and full Debug info enabled. I compile the Service (make sure no instance of the service in question is running, otherwise you can’t replace the binary image), start it (either from the SCM console or using other tools), get the exception dialog-box, hit Debug and choose the instance of VS which has the Service project open. I instantly get the file/line where the breakpoint exception is and from there I start debugging the Service. Also, this method preserves other breakpoints that you may end up adding to your session, and they are saved with your project files (typically in the .suo file).
Using this trick, the workflow is smooth and logical. I don’t have to do any extra and tedious work to get my service in debug mode other than simply choosing to debug it once I get the crash dialog-box. Beyond that, VS is up and running with the project files loaded, breakpoints set and all ready to attach to the Service Process in question. You really can’t attach to a process any faster than that and start debugging right away.