How Windows Debuggers Work

  • 5/15/2012

Script Debugging

Visual Studio also supports source-level debugging of script languages such as VBScript or JScript. This is internally implemented using the same in-process paradigm that managed-code debugging relies on. One of the reasons that the CLR used the in-process debugging model when it was first released to the public in 2002 was that script debugging had been successfully using it for years (since the mid-90s). In both cases, the debugger needs the script host’s or the CLR execution engine’s collaboration to support source-level debugging of the target process.

Architecture Overview

To understand how script debugging works, it’s useful to first explain a few basic concepts about how script languages are executed in Windows. The key to that architecture is the Active Scripting specification. This specification was introduced by Microsoft in the 90s and defines a set of COM interfaces to allow script languages that implement them to be hosted in any conforming host application. In Windows, both VBScript and JScript (Microsoft’s implementation of JavaScript) are Active Scripting languages whose implementation fully conforms with that specification.

The Active Scripting specification defines a language-processing engine, with the Active Scripting host using that engine when the script needs to be interpreted. Examples of Active Scripting engines are vbscript.dll and jscript.dll, which both ship with Windows under the system32 directory. Examples of Active Scripting hosts include the Internet Information Services (IIS) web server (server-side scripts embedded in ASP or ASP.NET pages), Internet Explorer (client-side script hosting in web pages), and the Windows scripting hosts (cscript.exe or wscript.exe) that ship with Windows and can be used to host scripts executed from a command prompt. There are also third-party Active Scripting engines to support other script languages, including Perl and Python.

In addition, the Active Scripting specification also defines a contract (a set of COM interfaces, again) for debuggers to take advantage of the host in their operations. An Active Scripting host that supports debugging (that is, implements the required COM interfaces) is called a smart host. All recent versions of Internet Explorer, IIS, and the Windows scripting hosts are smart hosts that implement those interfaces, which is at the heart of the magic that enables Visual Studio to debug scripts hosted by any of those processes. A Process Debug Manager (PDM) component (pdm.dll) is shipped with the Visual Studio debugger to insulate script engines from having to understand the intricacies of script debugging. In many ways, the PDM component serves the same purpose that the CLR runtime debugger controller thread and mscordbi.dll serve during managed debugging, as illustrated in Figure 3-7.

Figure 3-7

Figure 3-7 In-process script debugging architecture.

One way that Active Scripting debugging differs from managed-code debugging is that smart hosts usually do not expose their debugging services by default, whereas in the case of the CLR there is always a debugger thread running in the managed-code process. In Internet Explorer, for instance, you need to first enable script debugging in the host process by clearing the Disable Script Debugging option on the Tools\Internet Options\Advanced tab, as shown in Figure 3-8.

Figure 3-8

Figure 3-8 Enabling Internet Explorer script debugging.

In the same way, you need to explicitly enable debugging of scripts in the Windows scripting hosts (cscript.exe/wscript.exe) using the //X option if you want to also debug the executed scripts. The IIS web server manager also has a UI option for enabling server-side script debugging.

Debugging Scripts in Visual Studio

The following sample script from the companion source code, which simply displays its start time and arguments list to the console before exiting, will serve as a good example for how to use the //X option to enable script-debugging support in the cscript.exe host process and step through console scripts in Visual Studio.

//
// C:\book\code\chapter_03\script>test.js
//
var g_argv = new Array();

//
// store command-line parameters and call the main function
//
for (var i=0; i < WScript.Arguments.length; i++)
{
    g_argv.push(WScript.Arguments(i));
}

WScript.Quit(main(g_argv));

function main(argv)
{
    WScript.Echo("Script started at " + new Date());
    if (g_argv.length > 0)
    {
        WScript.Echo("Arguments: " + g_argv);
    }
}

Notice in particular the double slash in the //X option in the following command, which cscript.exe and wscript.exe use to distinguish their own options from the executed script’s options.

C:\Windows\system32\cscript.exe //X C:\book\code\chapter_03\script\test.js 1 2
Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.
...

When you run the preceding command on a machine with Visual Studio 2010 installed, you’ll be presented with a Visual Studio “attach” dialog box similar to the one shown in Figure 3-9. You might get another dialog box to consent to UAC elevation if you invoked the script from an elevated administrative command prompt, given that the Visual Studio debugger also needs to run elevated in that case.

Figure 3-9

Figure 3-9 Attaching to a script using the Visual Studio debugger.

You are then able to use the Visual Studio debugger to step through (using the F10 and F11 shortcuts) the script and debug it (with source-level information!), just as you would with any native-code or managed-code application, as shown in Figure 3-10.

Figure 3-10

Figure 3-10 Source-level script debugging using Visual Studio 2010.