Debugging Without a Debugger

Hi, my name is Todd Webb, I am an Escalation Engineer from the Global Escalation Services OEM Team.


I recently worked a case where we were trying to troubleshoot an issue and the system would hang with USB debugging enabled. This was a problem since USB debugging was the only kernel debugging option available on this particular hardware setup. I needed a quick and easy way to find the source of the problem without using many of the standard methods.  Basically I had to debug a debugger issue with no access to a debugger.  I knew the problem was likely USB related, but had no other information.  The method I used to troubleshoot this issue was to write some macros that would make a call to HalMakeBeep to generate audible indications of where we were in the code.  The primary reason for using this method was I could quickly and easily move the location in the code where I made the calls as I narrowed down where the problem occurred. 


The alternative would have been to add a bunch of logging and find some way to force a dump.  My initial assessment was this would be more time consuming and less flexible then the beep code method.  Others may have other methods to do this, but this just gives people another method of debugging driver start-up problems on systems that are not debuggable.


The main beep macro allows you to pass in a frequency and duration in milliseconds for a single beep.  Then based on the example below you can extend the single beep macro to create a series of beeps.


Here is an example of the macros I used:



// beep macros for troubleshooting without debugger



#define EHCI_BEEP1(f, d)                                              \

    {                                                                 \

        LARGE_INTEGER duration;                                       \

        duration.QuadPart = Int32x32To64(d, -10000);                  \

        HalMakeBeep(f);                                               \

        KeDelayExecutionThread(KernelMode, FALSE, &duration);         \

        HalMakeBeep(0);                                               \

        duration.QuadPart = Int32x32To64(500, -10000);                \

        KeDelayExecutionThread(KernelMode, FALSE, &duration);         \



#define EHCI_BEEP2(f, d)                                              \

    {                                                                 \

        EHCI_BEEP1(f, d);                                             \

        EHCI_BEEP1(f, d);                                             \



#define EHCI_BEEP3(f, d)                                              \

    {                                                                 \

        EHCI_BEEP2(f, d);                                             \

        EHCI_BEEP1(f, d);                                             \



Here is an example of a long beep followed by three short beeps:



    // debug – 1 long : 3 short


    EHCI_BEEP1(600, 1000);

    EHCI_BEEP3(600, 500);


Share this post :

Comments (3)

  1. C. Watford says:

    I think the Nuclear Navy guys I work with would appreciate debugging w/ morse code.

  2. calin iaru says:

    this is a new one – i would vote for logging + CrashOnCtrlScroll. haha

  3. C Webb says:

    Couldn’t you have also used kdprintf() and then used one of the utilities that displays kdprintf()s to a window? (Since writing to the window is asynchronous to the kdprintf()s, the output would trail the execution location in the USB/debug stack. In order to handle that you might be able to follow the kdprintf()s with KeDelayExecution (or similar) to make sure the kdprintf()s get written before the hang occurs.)

     <DIV class=commentowner>[

    The problem occurred too early in the boot process to use tools like DebugView.