Defrag Tools #170 - Debugger - JavaScript Scripting

Download this episode

Download Video

Description

In this episode of Defrag Tools, Andrew Richards talks to Andy Luhrs and Bill Messmer from the Debugging Tools for Windows team. We talk about the new JavaScript extensibility and scripting abilities in WinDbg available in the WDK and SDK build 14951 and newer.

 Bill leveraged the debugger object model previously in these episodes:

Timeline:

[00:00] Welcome and introductions
[00:24] New SDK drop
[00:29] Why JavaScript
[02:07] New commands
[03:50] Visual Studio Code
[04:00] Example - Hello World
[07:15] Debugger default namespaces
[09:07] Example - Print all threads
[10:26] Example - Conditional breakpoint
[18:13] 'g' vs. 'gc' – Andrew was right! 'gc' resumes execution in the same way that it started. So if you hit 'p' and then hit a conditional breakpoint that has 'gc' in it, the 'gc' will just finish your initial 'p'.
[20:40] Example - Unique stacks
[34:40] Example - Addition

Questions/Comments? Email us at defragtools@microsoft.com

JavaScript MSDN Docs:

 

Unique Stacks Example (the right one):

"use strict";

class __stackEntry
{
    constructor(frameString) {
        this.threads = [];
        this.frameString = frameString;
        this.children = new Map();
    }

    display(indent) 
    {
        for (var child of this.children.values())
        {
            host.diagnostics.debugLog(indent, child.frameString, " [Threads In Branch: ");
            for (var thread of child.threads)
            {
                host.diagnostics.debugLog(thread.Id, " ");
            }
            host.diagnostics.debugLog("]\n");
            child.display(indent + "    ");
        }
    }
}

class __stackMap
{
    constructor(process)
    {
        this.__process = process;
        this.__root = new __stackEntry("");
        this.build();
    }

    build()
    {
        for (var thread of this.__process.Threads)
        {
            var current = this.__root;
            var frameNum = 0;

            var frameCount = thread.Stack.Frames.Count();
            for (var frameNum = frameCount - 1; frameNum >= 0; --frameNum) {
                var frame = thread.Stack.Frames[frameNum];
                var frameString = frame.toString();
                if (current.children.has(frameString)) {
                    current = current.children.get(frameString);
                    current.threads.push(thread);
                }
                else {
                    var newEntry = new __stackEntry(frameString);
                    current.children.set(frameString, newEntry);
                    current = newEntry;
                    current.threads.push(thread);
                }
            }
        }
    }

    findEntry(thread)
    {
        var current = this.__root;
        var frameCount = thread.Stack.Frames.Count();
        for (var frameNum = frameCount - 1; frameNum >= 0; --frameNum)
        {
            var frame = thread.Stack.Frames[frameNum];
            var frameString = frame.toString();
            if (!current.children.has(frameString))
            {
                return null;
            }
            current = current.children.get(frameString);
        }
        return current;
    }

    display()
    {
        this.__root.display("");
    }
}

class __threadSameStacks
{
    constructor(thread)
    {
        this.__thread = thread;
    }

    getDimensionality()
    {
        return 1;
    }

    getValueAt(idx)
    {
        for (var idxVal of this)
        {
            var tid = idxVal[Symbol.indicies][0];
            if (idxVal[Symbol.indicies][0] == idx && tid != this.__thread.Id)
            {
                return idxVal.value;
            }
            return undefined;
        }
    }

    *[Symbol.iterator]()
    {
        var context = this.__thread.hostContext;
        var session = host.namespace.Debugger.Sessions.getValueAt(context);
        var process = session.Processes.getValueAt(context);
        var map = new __stackMap(process);
        var entry = map.findEntry(this.__thread);
        if (entry != null)
        {
            for (var sharingThread of entry.threads)
            {
                if (sharingThread.Id != this.__thread.Id)
                {
                    yield new host.indexedValue(sharingThread, [sharingThread.Id]);
                }
            }
        }
        
    }
}

class __threadExtension
{
    get IdenticalStacks()
    {
        return new __threadSameStacks(this);
    }
}


function invokeScript()
{
    var map = new __stackMap(host.currentProcess);
    map.display();
}

function initializeScript()
{
    return [new host.namedModelParent(__threadExtension, "Debugger.Models.Thread")];
}

Tag:

Debugging

Embed

Format

Available formats for this video:

Actual format may change based on video formats available and browser capability.

    The Discussion

    • User profile image
      ChicAlarm48

      I guess I shouldn't put off learning JavaScript any more. I won't miss having to write another debugger extension.

      Super interesting show, thanks guys!

    • User profile image
      Lieven

      What was the rationale to choose JavaScript over Powershell (if Powershell was even considered)? (not trying to bash anything, I think javascript support is great but genuinely curious)

    • User profile image
      Jaso

      Hi gents! Love the new look of the site - makes it a lot easier to navigate and looks really "clean". Haven't had chance to review the episode yet as I nearly had a heart failure when I first loaded the main page! The first words I read were: "Last episode". OMG! I thought you'd been disbanded and you'd posted that no more were going to be made! The day that happens, I'm retiring!!!

    Comments closed

    Comments have been closed since this content was published more than 30 days ago, but if you'd like to send us feedback you can Contact Us.