Useful service tricks - Debugging service startup

For the better part of the past 15 years, I've been working on one or another services for the Windows platform (not always services for windows, but always services ON windows).

Over that time, I've developed a bag of tricks for working with services, I mentioned one of them here.  Here's another.

One of the most annoying things to have to debug is a problem that occurs during service startup.  The problem is that you can't attach a debugger to the service until it's started, but if the service is failing during startup, that's hard.

It's possible to put a Sleep(10000) to cause your service startup to delay for 10 seconds (which gives you time to attach the debugger during start), that usually works, but sometimes service startup failures only happen on boot (for autostart services).

First off, before you start, you need to have a kernel debugger attached to your computer, and you need the debugging tools for windows (this gets you the command line debuggers).  I'm going to assume the debuggers are installed into "C:\Debuggers", obviously you need to adjust this for your local machine.

One thing to keep in mind: As far as I know, you need have the kernel debugger hooked up to debug service startup issues (you might be able to use ntsd.exe hooked up for remote debugging but I'm not sure if that will work). 

This of course begs the next question: "The kernel debugger?  Why on earth do I need a kernel debugger when I'm debugging user mode code?".  You're completely right.  But in this case, you're not actually using the kernel debugger.  Instead, you're running using a user mode debugger (ntsd.exe in my examples) that's running over the serial port using facilities that are enabled by the kernel debugger.  It's not quite the same thing.

There are multiple reasons for using a debugger that's redirected to a kernel debugger.  First off, if your service is an autostart service, it's highly likely that it starts long before the a user logs on.  So an interactive debugger won't really be able to debug the application.  Secondly, services by default can't interact with the desktop (heck, they often run in a different TS session from the user (this is especially true in Vista, but it's also true on XP with Fast User Switching), so they CAN'T interact with the desktop).  That means that when the debugger attempts to interact with the user, it can't because it flat-out can't because the desktop is sitting in a different TS session.

There are a couple of variants of this trick, all of which should work.

Lets start with the simplest:

If your service runs with a specific binary name, you can use the Image File Execution Options registry key (documented here) to launch your executable under the debugger.  The article linked shows how to launch using Visual Studio, for a service, you want to use the kernel debugger, so instead of using "devenv /debugexe" for the value, use "C:\Debuggers\NTSD.EXE -D", that will redirect the output to the kernel debugger.

 

Now for a somewhat more complicated version - You can ask the service controller to launch the debugger for you.  This is useful if your service is a shared service, or if it lives in an executable that's used for other purposes (if you use a specific -service command line switch to launch your exe as a service, for example).

This one's almost easier than the first.

From the command line, simply type:

sc config <your service short name> binpath= "c:\debuggers\ntsd.exe -d <path to your service executable> <your service executable options>

 

Now restart your service and it should pick up the change.

 

I suspect it's possible to use the ntsd.exe as a host process for remote debugging, I've never done that (I prefer assembly language debugging when I'm using the kernel debugger), so I don't feel comfortable describing how to set it up :(

Edit: Answered Purplet's question in the comments (answered it in the post because it was something important that I left out of the article).

Edit2: Thanks Ryan.  s/audiosrv/<your service>/