Delen via


Scripting voor JavaScript-foutopsporingsprogramma's

In dit onderwerp wordt beschreven hoe u JavaScript gebruikt om scripts te maken die inzicht hebben in foutopsporingsprogramma-objecten en de mogelijkheden van het foutopsporingsprogramma uitbreiden en aanpassen.

Overzicht van JavaScript Debugger Scripting

Scriptproviders koppelen een scripttaal aan het interne objectmodel van het foutopsporingsprogramma. Met de JavaScript-foutopsporingsprovider kunt u JavaScript gebruiken met de debugger.

Wanneer een JavaScript wordt geladen via de opdracht .scriptload, wordt de hoofdcode van het script uitgevoerd, worden de namen die aanwezig zijn in het script overbrugd naar de hoofdnaamruimte van het foutopsporingsprogramma (dx Debugger) en blijft het script in het geheugen aanwezig totdat het wordt verwijderd en alle verwijzingen naar de objecten worden vrijgegeven. Het script kan nieuwe functies bieden aan de expressie-evaluator van het foutopsporingsprogramma, het objectmodel van het foutopsporingsprogramma wijzigen of op ongeveer dezelfde manier fungeren als een visualisatieprogramma.

In dit onderwerp wordt beschreven wat u kunt doen met javaScript-foutopsporingsprogramma's.

Deze twee onderwerpen bevatten aanvullende informatie over het werken met JavaScript in het foutopsporingsprogramma.

Voorbeeldscripts voor javaScript-foutopsporingsprogramma's

Systeemeigen objecten in JavaScript-extensies

JavaScript-scriptingvideo

Defrag Tools #170 - Andy en Bill demonstreren JavaScript-uitbreidbaarheid en scriptingmogelijkheden in de debugger.

De JavaScript-provider voor foutopsporingsprogramma

De JavaScript-provider die is opgenomen in het foutopsporingsprogramma, profiteert optimaal van de nieuwste ECMAScript6-object- en klasseverbeteringen. Zie ECMAScript 6 — Nieuwe functies: Overzicht en vergelijking voor meer informatie.

JsProvider.dll

JsProvider.dll is de JavaScript-provider die wordt geladen ter ondersteuning van JavaScript Debugger Scripting.

Requirements

JavaScript Debugger Scripting is ontworpen voor gebruik met alle ondersteunde versies van Windows.

JavaScript Scripting Provider laden

Voordat u een van de .scriptopdrachten gebruikt, moet een scriptprovider worden geladen. Gebruik de opdracht .scriptproviders om te bevestigen dat de JavaScript-provider is geladen.

0:000> .scriptproviders
Available Script Providers:
    NatVis (extension '.NatVis')
    JavaScript (extension '.js')

JavaScript-metaopdrachten voor scripts

De volgende opdrachten zijn beschikbaar voor gebruik met JavaScript Debugger Scripting.

Requirements

Voordat u een van de .scriptopdrachten gebruikt, moet een scriptprovider worden geladen. Gebruik de opdracht .scriptproviders om te bevestigen dat de JavaScript-provider is geladen.

0:000> .scriptproviders
Available Script Providers:
    NatVis (extension '.NatVis')
    JavaScript (extension '.js')

.scriptproviders (Lijst scriptproviders)

Met de opdracht .scriptproviders worden alle scripttalen weergegeven die momenteel worden begrepen door het foutopsporingsprogramma en de extensie waaronder ze zijn geregistreerd.

In het onderstaande voorbeeld worden de JavaScript- en NatVis-providers geladen.

0:000> .scriptproviders
Available Script Providers:
    NatVis (extension '.NatVis')
    JavaScript (extension '.js')

Elk bestand eindigt op '. NatVis' wordt begrepen als een NatVis-script en elk bestand dat eindigt op '.js' wordt begrepen als een JavaScript-script. Elk type script kan worden geladen met de opdracht .scriptload.

Zie .scriptproviders (Lijst scriptproviders) voor meer informatie

.scriptload (script laden)

Met de opdracht .scriptload wordt een script geladen en wordt de hoofdcode van een script en de initializeScript-functie uitgevoerd. Als er fouten optreden tijdens de eerste belasting en uitvoering van het script, worden de fouten weergegeven in de console. De volgende opdracht toont het succesvolle laden van TestScript.js.

0:000> .scriptload C:\WinDbg\Scripts\TestScript.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\TestScript.js'

Alle objectmodelbewerkingen die door het script worden gemaakt, blijven aanwezig totdat het script vervolgens wordt verwijderd of opnieuw wordt uitgevoerd met andere inhoud.

Zie .scriptload (Load Script) voor meer informatie

.scriptrun

Met de opdracht .scriptrun wordt een script geladen, de hoofdcode van het script uitgevoerd, initializeScript en de invokeScript-functie . Als er fouten optreden tijdens de eerste belasting en uitvoering van het script, worden de fouten weergegeven in de console.

0:000> .scriptrun C:\WinDbg\Scripts\helloWorld.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\helloWorld.js'
Hello World!  We are in JavaScript!

Alle objectmodelbewerkingen van het foutopsporingsprogramma die door het script worden gemaakt, blijven aanwezig totdat het script vervolgens wordt verwijderd of opnieuw wordt uitgevoerd met andere inhoud.

Zie .scriptrun (Script uitvoeren) voor meer informatie.

.scriptunload (Script uitladen)

Met de opdracht .scriptunload wordt een geladen script uitgepakt en wordt de functie uninitializeScript aangeroepen. Gebruik de volgende opdrachtsyntaxis om een script te laden

0:000:x86> .scriptunload C:\WinDbg\Scripts\TestScript.js
JavaScript script unloaded from 'C:\WinDbg\Scripts\TestScript.js'

Zie .scriptunload (Script uitladen) voor meer informatie.

.scriptlist (geladen scripts weergeven)

Met de opdracht .scriptlist worden alle scripts weergegeven die zijn geladen via de .scriptload of de opdracht .scriptrun. Als testscript is geladen met behulp van .scriptload, wordt met de opdracht .scriptlist de naam van het geladen script weergegeven.

0:000> .scriptlist
Command Loaded Scripts:
    JavaScript script from 'C:\WinDbg\Scripts\TestScript.js'

Zie .scriptlist (Geladen scripts vermelden) voor meer informatie.

Aan de slag met JavaScript-foutopsporingsprogramma's

HelloWorld-voorbeeldscript

In deze sectie wordt beschreven hoe u een eenvoudig JavaScript-foutopsporingsprogrammascript maakt en uitvoert dat wordt afgedrukt, Hello World.

// WinDbg JavaScript sample
// Prints Hello World
function initializeScript()
{
    host.diagnostics.debugLog("***> Hello World! \n");
}

Gebruik een teksteditor zoals Kladblok om een tekstbestand met de naam HelloWorld.js te maken dat de Hierboven weergegeven JavaScript-code bevat.

Gebruik de opdracht .scriptload om het script te laden en uit te voeren. Omdat we de functienaam initializeScript hebben gebruikt, wordt de code in de functie uitgevoerd wanneer het script wordt geladen.

0:000> .scriptload c:\WinDbg\Scripts\HelloWorld.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\HelloWorld.js'
***> Hello World! 

Nadat het script is geladen, is de extra functionaliteit beschikbaar in het foutopsporingsprogramma. Gebruik de opdracht dx (Display NatVis Expression) om Debugger.State.Scripts weer te geven om te zien dat ons script nu resident is.

0:000> dx Debugger.State.Scripts
Debugger.State.Scripts                
    HelloWorld 

In het volgende voorbeeld gaan we een benoemde functie toevoegen en aanroepen.

Voorbeeldscript met twee waarden toevoegen

In deze sectie wordt beschreven hoe u een eenvoudige JavaScript-debuggerscript maakt en uitvoert die invoer ontvangt en twee getallen optelt.

Dit eenvoudige script biedt één functie, addTwoValues.

// WinDbg JavaScript sample
// Adds two functions
function addTwoValues(a, b)
 {
     return a + b;
 }

Gebruik een teksteditor zoals Kladblok om een tekstbestand te maken met de naam FirstSampleFunction.js

Gebruik de opdracht .scriptload om het script te laden.

0:000> .scriptload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'

Nadat het script is geladen, is de extra functionaliteit beschikbaar in het foutopsporingsprogramma. Gebruik de opdracht dx (Display NatVis Expression) om Debugger.State.Scripts weer te geven om te zien dat ons script nu resident is.

0:000> dx Debugger.State.Scripts
Debugger.State.Scripts                
    FirstSampleFunction    

We kunnen de FirstSampleFunction selecteren om te zien welke functies het biedt.

0:000> dx -r1 -v Debugger.State.Scripts.FirstSampleFunction.Contents
Debugger.State.Scripts.FirstSampleFunction.Contents                 : [object Object]
    host             : [object Object]
    addTwoValues    
 ... 

Als u het script wat handiger wilt maken om mee te werken, wijst u een variabele in het foutopsporingsprogramma toe om de inhoud van het script vast te houden met behulp van de dx-opdracht.

0:000> dx @$myScript = Debugger.State.Scripts.FirstSampleFunction.Contents

Gebruik de dx-expressie-evaluator om de functie addTwoValues aan te roepen.

0:000> dx @$myScript.addTwoValues(10, 41),d
@$myScript.addTwoValues(10, 41),d : 51

U kunt ook de ingebouwde alias @$scriptContents gebruiken om met de scripts te werken. Met de alias @$scriptContents wordt de .Content van alle scripts die worden geladen samengevoegd.

0:001> dx @$scriptContents.addTwoValues(10, 40),d
@$scriptContents.addTwoValues(10, 40),d : 50

Wanneer u klaar bent met het werken met het script, gebruikt u de opdracht .scriptunload om het script te ontladen.

0:000> .scriptunload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully unloaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'

Automatisering van debuggercommando's

In deze sectie wordt beschreven hoe u een eenvoudig JavaScript-foutopsporingsprogrammascript maakt en uitvoert waarmee het verzenden van de opdracht u (unassemble) wordt geautomatiseerd. In het voorbeeld ziet u ook hoe u opdrachtuitvoer in een lus verzamelt en weergeeft.

Dit script biedt één functie, RunCommands().

// WinDbg JavaScript sample
// Shows how to call a debugger command and display results
"use strict";

function RunCommands()
{
var ctl = host.namespace.Debugger.Utility.Control;   
var output = ctl.ExecuteCommand("u");
host.diagnostics.debugLog("***> Displaying command output \n");

for (var line of output)
   {
   host.diagnostics.debugLog("  ", line, "\n");
   }

host.diagnostics.debugLog("***> Exiting RunCommands Function \n");

}

Gebruik een teksteditor zoals Kladblok om een tekstbestand te maken met de naam RunCommands.js

Gebruik de opdracht .scriptload om het RunCommands-script te laden.

0:000> .scriptload c:\WinDbg\Scripts\RunCommands.js 
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\RunCommands.js'

Nadat het script is geladen, is de extra functionaliteit beschikbaar in het foutopsporingsprogramma. Gebruik de opdracht dx (Display NatVis Expression) om Debugger.State.Scripts.RunCommands weer te geven om te zien dat ons script nu resident is.

0:000>dx -r3 Debugger.State.Scripts.RunCommands
Debugger.State.Scripts.RunCommands                
    Contents         : [object Object]
        host             : [object Object]
            diagnostics      : [object Object]
            namespace       
            currentSession   : Live user mode: <Local>
            currentProcess   : notepad.exe
            currentThread    : ntdll!DbgUiRemoteBreakin (00007ffd`87f2f440) 
            memory           : [object Object]

Gebruik de dx-opdracht om de functie RunCommands aan te roepen in het script RunCommands.

0:000> dx Debugger.State.Scripts.RunCommands.Contents.RunCommands()
  ***> Displaying command output
  ntdll!ExpInterlockedPopEntrySListEnd+0x17 [d:\rs1\minkernel\ntos\rtl\amd64\slist.asm @ 196]:
  00007ffd`87f06e67 cc              int     3
  00007ffd`87f06e68 cc              int     3
  00007ffd`87f06e69 0f1f8000000000  nop     dword ptr [rax]
  ntdll!RtlpInterlockedPushEntrySList [d:\rs1\minkernel\ntos\rtl\amd64\slist.asm @ 229]:
  00007ffd`87f06e70 0f0d09          prefetchw [rcx]
  00007ffd`87f06e73 53              push    rbx
  00007ffd`87f06e74 4c8bd1          mov     r10,rcx
  00007ffd`87f06e77 488bca          mov     rcx,rdx
  00007ffd`87f06e7a 4c8bda          mov     r11,rdx
***> Exiting RunCommands Function

Speciale JavaScript-foutopsporingsprogrammafuncties

Er zijn verschillende speciale functies in een JavaScript-script dat wordt aangeroepen door de scriptprovider zelf.

initializeScript

Wanneer een JavaScript-script wordt geladen en uitgevoerd, doorloopt het een reeks stappen voordat de variabelen, functies en andere objecten in het script van invloed zijn op het objectmodel van het foutopsporingsprogramma.

  • Het script wordt in het geheugen geladen en geparseerd.
  • De hoofdcode in het script wordt uitgevoerd.
  • Als het script een methode met de naam initializeScript heeft, wordt die methode aangeroepen.
  • De retourwaarde van initializeScript wordt gebruikt om te bepalen hoe het objectmodel van het foutopsporingsprogramma automatisch moet worden gewijzigd.
  • De namen in het script worden gekoppeld aan de naamruimte van de debugger.

Zoals vermeld, wordt initializeScript onmiddellijk aangeroepen nadat de hoofdcode van het script is uitgevoerd. De taak is om een JavaScript-matrix met registratieobjecten te retourneren aan de provider die aangeeft hoe het objectmodel van het foutopsporingsprogramma moet worden gewijzigd.

function initializeScript()
{
    // Add code here that you want to run every time the script is loaded. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***> initializeScript was called\n");
}

invokeScript

De invokeScript-methode is de primaire scriptmethode en wordt aangeroepen wanneer .scriptload en .scriptrun worden uitgevoerd.

function invokeScript()
{
    // Add code here that you want to run every time the script is executed. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***> invokeScript was called\n");
}

uninitializeScript

De methode uninitializeScript is de gedragsmatige tegengesteldheid van de methode initializeScript. Deze wordt aangeroepen wanneer een script niet is gekoppeld en klaar is om te worden uitgeladen. Het is de taak om wijzigingen in het objectmodel ongedaan te maken die het script imperatief heeft gemaakt tijdens de uitvoering en/of om objecten te vernietigen die door het script in de cache zijn opgeslagen.

Als een script geen imperatieve bewerkingen voor het objectmodel maakt of resultaten in de cache opgeslagen, hoeft het geen uninitializeScript-methode te hebben. Wijzigingen in het objectmodel die worden uitgevoerd zoals aangegeven door de retourwaarde van initializeScript, worden automatisch ongedaan gemaakt door de provider. Voor dergelijke wijzigingen is geen expliciete uninitializeScript-methode vereist.

function uninitializeScript()
{
    // Add code here that you want to run every time the script is unloaded. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***> uninitialize was called\n");
}

Samenvatting van functies die worden aangeroepen door scriptopdrachten

Deze tabel geeft een overzicht van welke functies worden aangeroepen door de scriptopdrachten

Opdracht .scriptload .scriptrun (script uitvoeren) .scriptunload (Script uitladen)
wortel ja ja
initializeScript ja ja
invokeScript ja
uninitializeScript ja

Gebruik deze voorbeeldcode om te zien wanneer elke functie wordt aangeroepen als het script wordt geladen, uitgevoerd en uitgeladen.

// Root of Script
host.diagnostics.debugLog("***>; Code at the very top (root) of the script is always run \n");


function initializeScript()
{
    // Add code here that you want to run every time the script is loaded. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***>; initializeScript was called \n");
}

function invokeScript()
{
    // Add code here that you want to run every time the script is executed. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***>; invokeScript was called \n");
}


function uninitializeScript()
{
    // Add code here that you want to run every time the script is unloaded. 
    // We will just send a message to indicate that function was called.
    host.diagnostics.debugLog("***>; uninitialize was called\n");
}


function main()
{
    // main is just another function name in JavaScript
    // main is not called by .scriptload or .scriptrun  
    host.diagnostics.debugLog("***>; main was called \n");
}

Een foutopsporingsprogramma visualiseren maken in JavaScript

Met aangepaste visualisatiebestanden kunt u gegevens groeperen en ordenen in een visualisatiestructuur die de gegevensrelaties en inhoud beter weerspiegelt. U kunt de JavaScript-extensie voor foutopsporingsprogramma's gebruiken om visuals voor foutopsporingsprogramma's te schrijven die op een manier vergelijkbaar zijn met NatVis. Dit wordt bereikt via het ontwerpen van een JavaScript-prototypeobject (of een ES6-klasse) die fungeert als de visualizer voor een bepaald gegevenstype. Zie dx (Display NatVis Expression) voor meer informatie over NatVis en het foutopsporingsprogramma.

Voorbeeldklasse - Simple1DArray

Bekijk een voorbeeld van een C++-klasse die een enkele dimensionale matrix vertegenwoordigt. Deze klasse heeft twee leden, m_size de totale grootte van de matrix en m_pValues die een aanwijzer is naar een aantal ints in het geheugen die gelijk zijn aan het m_size veld.

class Simple1DArray
{
private:

    ULONG64 m_size;
    int *m_pValues;
};

We kunnen de dx-opdracht gebruiken om de standaardgegevensstructuurweergave te bekijken.

0:000> dx g_array1D
g_array1D                 [Type: Simple1DArray]
    [+0x000] m_size           : 0x5 [Type: unsigned __int64]
    [+0x008] m_pValues        : 0x8be32449e0 : 0 [Type: int *]

JavaScript Visualizer

Om dit type te visualiseren, moeten we een prototypeklasse (of ES6) maken die alle velden en eigenschappen bevat die het foutopsporingsprogramma moet weergeven. We moeten ook de initializeScript-methode een object laten retourneren dat de JavaScript-provider opdraagt ons prototype te koppelen als visualizer voor het opgegeven type.

function initializeScript()
{
    //
    // Define a visualizer class for the object.
    //
    class myVisualizer
    {
        //
        // Create an ES6 generator function which yields back all the values in the array.
        //
        *[Symbol.iterator]()
        {
            var size = this.m_size;
            var ptr = this.m_pValues;
            for (var i = 0; i < size; ++i)
            {
                yield ptr.dereference();

                //
                // Note that the .add(1) method here is effectively doing pointer arithmetic on
                // the underlying pointer.  It is moving forward by the size of 1 object.
                //
                ptr = ptr.add(1);
            }
        }
    }

    return [new host.typeSignatureRegistration(myVisualizer, "Simple1DArray")];
}

Sla het script op in een bestand met de naam arrayVisualizer.js.

Gebruik de opdracht .load (Load Extension DLL) om de JavaScript-provider te laden.

0:000> .load C:\ScriptProviders\jsprovider.dll

Gebruik .scriptload om het script voor matrix visualiseren te laden.

0:000> .scriptload c:\WinDbg\Scripts\arrayVisualizer.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\arrayVisualizer.js'

Nu worden bij gebruik van de dx-opdracht de rijen met matrixinhoud weergegeven in de script-visualisator.

0:000> dx g_array1D
g_array1D                 : [object Object] [Type: Simple1DArray]
    [<Raw View>]     [Type: Simple1DArray]
    [0x0]            : 0x0
    [0x1]            : 0x1
    [0x2]            : 0x2
    [0x3]            : 0x3
    [0x4]            : 0x4

Bovendien biedt deze JavaScript-visualisatie LINQ-functionaliteit, zoals Selecteren.

0:000> dx g_array1D.Select(n => n * 3),d
g_array1D.Select(n => n * 3),d                
    [0]              : 0
    [1]              : 3
    [2]              : 6
    [3]              : 9
    [4]              : 12

Wat van invloed is op de visualisatie

Een prototype of klasse die de visualizer voor een systeemeigen type maakt via een retour van een host.typeSignatureRegistration-object uit initializeScript, bevat alle eigenschappen en methoden in JavaScript die zijn toegevoegd aan het systeemeigen type. Daarnaast zijn de volgende semantiek van toepassing:

  • Elke naam die niet begint met twee onderstrepingstekens (__), is beschikbaar in de visualisatie.

  • Namen die deel uitmaken van standaard JavaScript-objecten of die deel uitmaken van protocollen die door de JavaScript-provider worden gemaakt, worden niet weergegeven in de visualisatie.

  • Een object kan worden itereerbaar gemaakt via de ondersteuning van [Symbol.iterator].

  • Een object kan worden geïndexeerd via de ondersteuning van een aangepast protocol dat bestaat uit verschillende functies: getDimensionality, getValueAt en optioneel setValueAt.

Native en JavaScript Object Bridge

De brug tussen JavaScript en het objectmodel van het foutopsporingsprogramma is in twee richtingen. Systeemeigen objecten kunnen worden doorgegeven aan JavaScript en JavaScript-objecten kunnen worden doorgegeven aan de expressie-evaluator van de debugger. Bekijk als voorbeeld hiervan de toevoeging van de volgende methode in ons script:

function multiplyBySeven(val)
{
    return val * 7;
}

Deze methode kan nu worden gebruikt in de bovenstaande LINQ-voorbeeldquery. Eerst laden we de JavaScript-visualisatie.

0:000> .scriptload c:\WinDbg\Scripts\arrayVisualizer2.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\arrayVisualizer2.js'

0:000> dx @$myScript = Debugger.State.Scripts.arrayVisualizer2.Contents

Vervolgens kunnen we de functie multiplyBySeven inline gebruiken, zoals hieronder wordt weergegeven.

0:000> dx g_array1D.Select(@$myScript.multiplyBySeven),d
g_array1D.Select(@$myScript.multiplyBySeven),d                
    [0]              : 0
    [1]              : 7
    [2]              : 14
    [3]              : 21
    [4]              : 28

Voorwaardelijke onderbrekingspunten met JavaScript

U kunt JavaScript gebruiken om aanvullende verwerking uit te voeren nadat een onderbrekingspunt is bereikt. Script kan bijvoorbeeld worden gebruikt om andere runtimewaarden te onderzoeken en vervolgens te bepalen of u automatisch de uitvoering van code wilt voortzetten of stoppen en aanvullende handmatige foutopsporing wilt uitvoeren.

Zie Methoden voor het beheren van onderbrekingspunten voor algemene informatie over het werken met onderbrekingspunten.

DebugHandler.js voorbeeldscript voor het verwerken van onderbrekingspunten

In dit voorbeeld worden het open- en opslaandialoogvenster van kladblok geëvalueerd: kladblok!ShowOpenSaveDialog. Met dit script wordt de pszCaption-variabele geëvalueerd om te bepalen of het huidige dialoogvenster een dialoogvenster Openen is of het een dialoogvenster Opslaan als is. Als het een geopend dialoogvenster is, wordt de uitvoering van code voortgezet. Als het een Opslaan als-dialoogvenster is, wordt de uitvoering van de code gestopt en wordt de debugger onderbroken.

 // Use JavaScript strict mode 
"use strict";

// Define the invokeScript method to handle breakpoints

 function invokeScript()
 {
    var ctl = host.namespace.Debugger.Utility.Control;

    //Get the address of my string
    var address = host.evaluateExpression("pszCaption");

    // The open and save dialogs use the same function
    // When we hit the open dialog, continue.
    // When we hit the save dialog, break.
    if (host.memory.readWideString(address) == "Open") {
        // host.diagnostics.debugLog("We're opening, let's continue!\n");
        ctl.ExecuteCommand("gc");
    }
    else
    {
        //host.diagnostics.debugLog("We're saving, let's break!\n");
    }
  }

Met deze opdracht stelt u een onderbrekingspunt in op notepad!ShowOpenSaveDialog en zal het hierboven weergegeven script worden uitgevoerd wanneer dat onderbrekingspunt wordt bereikt.

bp notepad!ShowOpenSaveDialog ".scriptrun C:\\WinDbg\\Scripts\\DebugHandler.js"

Wanneer de optie Bestand > opslaan in Kladblok is geselecteerd, wordt het script uitgevoerd, treedt er een onderbreking in de uitvoering van de code op, en wordt de g-opdracht niet verzonden.

JavaScript script successfully loaded from 'C:\WinDbg\Scripts\DebugHandler.js'
notepad!ShowOpenSaveDialog:
00007ff6`f9761884 48895c2408      mov     qword ptr [rsp+8],rbx ss:000000db`d2a9f2f0=0000021985fe2060

Werken met 64-bits waarden in JavaScript-extensies

In deze sectie wordt beschreven hoe 64-bits waarden die worden doorgegeven aan een JavaScript-extensie voor foutopsporingsprogramma's zich gedragen. Dit probleem treedt op omdat JavaScript alleen de mogelijkheid heeft om getallen op te slaan met 53 bits.

64-bit en JavaScript 53-bit opslag

Ordinale waarden die worden doorgegeven aan JavaScript, worden normaal gesproken vertaald als JavaScript-getallen. Het probleem is dat JavaScript-getallen 64-bits drijvendekommawaarden met dubbele precisie zijn. Elke rangtel van meer dan 53 bits verliest precisie bij het invoeren in JavaScript. Dit is een probleem voor 64-bits aanwijzers en andere 64-bits ordinale waarden die vlaggen in de hoogste bytes kunnen bevatten. Om dit te behandelen, komt elke 64-bits systeemeigen waarde (of deze nu uit systeemeigen code of het gegevensmodel komt) in JavaScript binnen als een bibliotheektype, niet als een JavaScript-nummer. Dit bibliotheektype retourneert terug naar systeemeigen code zonder dat er numerieke precisie verloren gaat.

Automatische conversie

Het bibliotheektype voor 64-bits ordinale waarden ondersteunt de standaard JavaScript-waardeOf-conversie. Als het object wordt gebruikt in een wiskundige bewerking of een andere constructie waarvoor waardeconversie is vereist, wordt het automatisch geconverteerd naar een JavaScript-getal. Als er verlies van precisie optreedt (de waarde maakt gebruik van meer dan 53 bits met ordinale precisie), zal de JavaScript-provider een uitzondering genereren.

Houd er rekening mee dat als u bitwise operators in JavaScript gebruikt, u beperkt bent tot een ordinale precisie van 32-bits.

Deze voorbeeldcode telt twee getallen op en wordt gebruikt om de conversie van 64-bits waarden te testen.

function playWith64BitValues(a64, b64)
{
    // Sum two numbers to demonstrate 64-bit behavior.
    //
    // Imagine a64==100, b64==1000
    // The below would result in sum==1100 as a JavaScript number.  No exception is thrown.  The values auto-convert.
    //
    // Imagine a64==2^56, b64=1
    // The below will **Throw an Exception**.  Conversion to numeric results in loss of precision!
    //
    var sum = a64 + b64;
    host.diagnostics.debugLog("Sum   >> ", sum, "\n");

}

function performOp64BitValues(a64, b64, op)
{
    //
    // Call a data model method passing 64-bit value.  There is no loss of precision here.  This round trips perfectly.
    // For example:
    //  0:000> dx @$myScript.playWith64BitValues(0x4444444444444444ull, 0x3333333333333333ull, (x, y) => x + y)
    //  @$myScript.playWith64BitValues(0x4444444444444444ull, 0x3333333333333333ull, (x, y) => x + y) : 0x7777777777777777
    //
    return op(a64, b64);
}

Gebruik een teksteditor zoals Kladblok om een tekstbestand te maken met de naam PlayWith64BitValues.js

Gebruik de opdracht .scriptload om het script te laden.

0:000> .scriptload c:\WinDbg\Scripts\PlayWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\PlayWith64BitValues.js'

Als u het script wat handiger wilt maken om mee te werken, wijst u een variabele in het foutopsporingsprogramma toe om de inhoud van het script vast te houden met behulp van de dx-opdracht.

0:000> dx @$myScript = Debugger.State.Scripts.PlayWith64BitValues.Contents

Gebruik de dx-expressie-evaluator om de functie addTwoValues aan te roepen.

Eerst berekenen we de waarde van 2^53 =9007199254740992 (Hex 0x20000000000000).

Eerst om te testen, gebruiken we (2^53) - 2 en zien we dat deze de juiste waarde voor de som retourneert.

0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740990)
Sum   >> 18014398509481980

Vervolgens berekenen we (2^53) -1 =9007199254740991. Hiermee wordt de fout geretourneerd die aangeeft dat het conversieproces precisie verliest, dus dit is de grootste waarde die kan worden gebruikt met de sommethode in JavaScript-code.

0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number

Roep een gegevensmodelmethode aan die 64-bits waarden doorgeeft. Er is hier geen verlies van precisie.

0:001> dx @$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF,  0x7FFFFFFFFFFFFFFF, (x, y) => x + y)
@$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF,  0x7FFFFFFFFFFFFFFF, (x, y) => x + y) : 0xfffffffffffffffe

Vergelijking

Het 64-bits bibliotheektype is een JavaScript-object en geen waardetype zoals een JavaScript-nummer. Dit heeft enkele gevolgen voor vergelijkingsbewerkingen. Normaal gesproken geeft gelijkheid (==) op een object aan dat operanden naar hetzelfde object verwijzen en niet naar dezelfde waarde. De JavaScript-provider beperkt dit door liveverwijzingen bij te houden naar 64-bits waarden en hetzelfde 'onveranderbare' object te retourneren voor niet-verzamelde 64-bits waarde. Dit betekent dat er ter vergelijking het volgende zou gebeuren.

// Comparison with 64 Bit Values

function comparisonWith64BitValues(a64, b64)
{
    //
    // No auto-conversion occurs here.  This is an *EFFECTIVE* value comparison.  This works with ordinals with above 53-bits of precision.
    //
    var areEqual = (a64 == b64);
    host.diagnostics.debugLog("areEqual   >> ", areEqual, "\n");
    var areNotEqual = (a64 != b64);
    host.diagnostics.debugLog("areNotEqual   >> ", areNotEqual, "\n");

    //
    // Auto-conversion occurs here.  This will throw if a64 does not pack into a JavaScript number with no loss of precision.
    //
    var isEqualTo42 = (a64 == 42);
    host.diagnostics.debugLog("isEqualTo42   >> ", isEqualTo42, "\n");
    var isLess = (a64 < b64);
    host.diagnostics.debugLog("isLess   >> ", isLess, "\n");

Gebruik een teksteditor zoals Kladblok om een tekstbestand te maken met de naam ComparisonWith64BitValues.js

Gebruik de opdracht .scriptload om het script te laden.

0:000> .scriptload c:\WinDbg\Scripts\ComparisonWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\ComparisonWith64BitValues.js'

Als u het script wat handiger wilt maken om mee te werken, wijst u een variabele in het foutopsporingsprogramma toe om de inhoud van het script vast te houden met behulp van de dx-opdracht.

0:000> dx @$myScript = Debugger.State.Scripts.comparisonWith64BitValues.Contents

Eerst om te testen, gebruiken we (2^53) - 2 en zien we dat deze de verwachte waarden retourneert.

0:001> dx @$myScript.comparisonWith64BitValues(9007199254740990, 9007199254740990)
areEqual   >> true
areNotEqual   >> false
isEqualTo42   >> false
isLess   >> false

We proberen ook het getal 42 als de eerste waarde om te controleren of de vergelijkingsoperator werkt zoals het zou moeten.

0:001> dx @$myScript.comparisonWith64BitValues(42, 9007199254740990)
areEqual   >> false
areNotEqual   >> true
isEqualTo42   >> true
isLess   >> true

Vervolgens berekenen we (2^53) -1 =9007199254740991. Deze waarde retourneert de fout die aangeeft dat het conversieproces precisie verliest, dus dit is de grootste waarde die kan worden gebruikt met de vergelijkingsoperatoren in JavaScript-code.

0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number

Precisie in bewerkingen behouden

Om een foutopsporingsprogramma-extensie de precisie te laten behouden, wordt een set wiskundige functies geprojecteerd boven op het 64-bits bibliotheektype. Als de extensie meer precisie nodig heeft dan 53 bits voor binnenkomende 64-bits waarden, moeten de volgende methoden worden gebruikt in plaats van te vertrouwen op standaardoperators:

Methodenaam handtekening Beschrijving
asNumber .asNumber() Converteert de 64-bits waarde naar een JavaScript-getal. Als er sprake is van verlies van precisie, wordt **EEN UITZONDERING GEGENEREERD**
convertToNumber .convertToNumber() Converteert de 64-bits waarde naar een JavaScript-getal. Als er sprake is van precisieverlies, wordt **GEEN UITZONDERING GEGENEREERD**
getLowPart .getLowPart() Converteert de lagere 32 bits van de 64-bits waarde naar een JavaScript-getal
getHighPart .getHighPart() Converteert de hoge 32 bits van de 64-bits waarde naar een JavaScript-getal
toevoegen .add(value) Voegt een waarde toe aan de 64-bits waarde en retourneert het resultaat
aftrekken .aftrekken(waarde) Trekt een waarde af van de 64-bits waarde en retourneert het resultaat
vermenigvuldigen .multiply(value) Vermenigvuldigt de 64-bits waarde met de opgegeven waarde en retourneert het resultaat
divide .divide(value) Verdeelt de 64-bits waarde door de opgegeven waarde en retourneert het resultaat
bitwiseAnd .bitwiseAnd(waarde) Berekent de bitsgewijze en van de 64-bits waarde met de opgegeven waarde en retourneert het resultaat
bitwiseOr .bitwiseOr(waarde) Berekent de bitsgewijze of van de 64-bits waarde met de opgegeven waarde en retourneert het resultaat.
bitwiseXor .bitwiseXor(waarde) Berekent de bitsgewijze xor van de 64-bits waarde met de opgegeven waarde en retourneert het resultaat
bitwiseShiftLeft .bitwiseShiftLeft(waarde) Hiermee wordt de 64-bits waarde naar links verplaatst door de opgegeven hoeveelheid en wordt het resultaat geretourneerd
bitwiseShiftRight .bitwiseShiftRight(waarde) De 64-bits waarde wordt naar rechts verschoven met de opgegeven hoeveelheid en het resultaat wordt geretourneerd.
toString .toString([radix]) Converteert de 64-bits waarde naar een weergavetekenreeks in de standaard radix (of de optioneel opgegeven radix)

Deze methode is ook beschikbaar.

Methodenaam handtekening Beschrijving
compareTo .compareTo(value) Vergelijkt de 64-bits waarde met een andere 64-bits waarde.

JavaScript-foutopsporing

In deze sectie wordt beschreven hoe u de mogelijkheden voor scriptopsporing van het foutopsporingsprogramma gebruikt. Het foutopsporingsprogramma heeft geïntegreerde ondersteuning voor het opsporen van fouten in JavaScript-scripts met behulp van de opdracht .scriptdebug (Debug JavaScript).

Opmerking

Als u JavaScript-foutopsporing met WinDbg wilt gebruiken, voert u het foutopsporingsprogramma uit als administrator.

Gebruik deze voorbeeldcode om foutopsporing van een JavaScript te verkennen. Voor dit scenario noemen we deze DebuggableSample.js en slaan we deze op in de map C:\MyScripts.

"use strict";

class myObj
{
    toString()
    {
        var x = undefined[42];
        host.diagnostics.debugLog("BOO!\n");
    }
}

class iterObj
{
    *[Symbol.iterator]()
    {
        throw new Error("Oopsies!");
    }
}

function foo()
{
    return new myObj();
}

function iter()
{
    return new iterObj();
}

function throwAndCatch()
{
    var outer = undefined;
    var someObj = {a : 99, b : {c : 32, d: "Hello World"} };
    var curProc = host.currentProcess;
    var curThread = host.currentThread;

    try
    {
        var x = undefined[42];
    } catch(e) 
    {
        outer = e;
    }

    host.diagnostics.debugLog("This is a fun test\n");
    host.diagnostics.debugLog("Of the script debugger\n");
    var foo = {a : 99, b : 72};
    host.diagnostics.debugLog("foo.a = ", foo.a, "\n");

    return outer;
}

function throwUnhandled()
{
    var proc = host.currentProcess;
    var thread = host.currentThread;
    host.diagnostics.debugLog("Hello...  About to throw an exception!\n");
    throw new Error("Oh me oh my!  This is an unhandled exception!\n");
    host.diagnostics.debugLog("Oh...  this will never be hit!\n");
    return proc;
}

function outer()
{
    host.diagnostics.debugLog("inside outer!\n");
    var foo = throwAndCatch();
    host.diagnostics.debugLog("Caught and returned!\n");
    return foo;
}

function outermost()
{
    var x = 99;
    var result = outer();
    var y = 32;
    host.diagnostics.debugLog("Test\n");
    return result;
}

function initializeScript()
{
    //
    // Return an array of registration objects to modify the object model of the debugger
    // See the following for more details:
    //
    //     https://aka.ms/JsDbgExt
    //
}

Laad het voorbeeldscript.

.scriptload C:\MyScripts\DebuggableSample.js

Start actief foutopsporing van het script met behulp van de opdracht .scriptdebug .

0:000> .scriptdebug C:\MyScripts\DebuggableSample.js
>>> ****** DEBUGGER ENTRY DebuggableSample ******
           No active debug event!

>>> Debug [DebuggableSample <No Position>] >

Zodra u de prompt >>> Debug [DebuggableSample <No Position>] > en een aanvraag voor invoer ziet, bevindt u zich in het foutopsporingsprogramma voor scripts.

Gebruik de opdracht .help om een lijst met opdrachten weer te geven in de JavaScript-foutopsporingsomgeving.

>>> Debug [DebuggableSample <No Position>] >.help
Script Debugger Commands (*NOTE* IDs are **PER SCRIPT**):
    ? .................................. Get help
    ? <expr>  .......................... Evaluate expression <expr> and display result
    ?? <expr>  ......................... Evaluate expression <expr> and display result
    |  ................................. List available scripts
    |<scriptid>s  ...................... Switch context to the given script
    bc \<bpid\>  ......................... Clear breakpoint by specified \<bpid\>
    bd \<bpid\>  ......................... Disable breakpoint by specified \<bpid\>
    be \<bpid\>  ......................... Enable breakpoint by specified \<bpid\>
    bl  ................................ List breakpoints
    bp <line>:<column>  ................ Set breakpoint at the specified line and column
    bp <function-name>  ................ Set breakpoint at the (global) function specified by the given name
    bpc  ............................... Set breakpoint at current location
    dv  ................................ Display local variables of current frame
    g  ................................. Continue script
    gu   ............................... Step out
    k  ................................. Get stack trace
    p  ................................. Step over
    q  ................................. Exit script debugger (resume execution)
    sx  ................................ Display available events/exceptions to break on
    sxe <event>  ....................... Enable break on <event>
    sxd <event>  ....................... Disable break on <event>
    t  ................................. Step in
    .attach <scriptId>  ................ Attach debugger to the script specified by <scriptId>
    .detach [<scriptId>]  .............. Detach debugger from the script specified by <scriptId>
    .frame <index>  .................... Switch to frame number <index>
    .f+  ............................... Switch to next stack frame
    .f-  ............................... Switch to previous stack frame
    .help  ............................. Get help

Gebruik het sx-script debugger-commando om de lijst met gebeurtenissen te bekijken die we kunnen onderscheppen.

>>> Debug [DebuggableSample <No Position>] >sx              
sx                                                          
    ab  [   inactive] .... Break on script abort            
    eh  [   inactive] .... Break on any thrown exception    
    en  [   inactive] .... Break on entry to the script     
    uh  [     active] .... Break on unhandled exception     

Gebruik de sxe-scriptdebuggeropdracht om onderbreking bij start in te schakelen, zodat het script overgaat naar de script-debugger zodra er code in wordt uitgevoerd.

>>> Debug [DebuggableSample <No Position>] >sxe en          
sxe en                                                      
Event filter 'en' is now active                             

Sluit het foutopsporingsprogramma voor scripts af en we voeren een functieaanroep uit naar het script dat in het foutopsporingsprogramma trapt.

>>> Debug [DebuggableSample <No Position>] >q

Op dit moment bent u weer terug in de normale debugger. Voer de volgende opdracht uit om het script aan te roepen.

dx @$scriptContents.outermost()

U bent nu terug in het scriptdebugger en is ingebroken op de eerste regel van de buitenste JavaScript-functie.

>>> ****** SCRIPT BREAK DebuggableSample [BreakIn] ******   
           Location: line = 73, column = 5                  
           Text: var x = 99                                 

>>> Debug [DebuggableSample 73:5] >                         

Naast het zien van de onderbreking in het foutopsporingsprogramma, krijgt u informatie over de regel (73) en de kolom (5) waar de onderbreking heeft plaatsgevonden, evenals het relevante codefragment van de broncode: var x = 99.

Laten we een paar keer stappen en naar een andere plek in het script gaan.

    p
    t
    p
    t
    p
    p

Op dit moment moet u worden onderverdeeld in de methode throwAndCatch op regel 34.

...
>>> ****** SCRIPT BREAK DebuggableSample [Step Complete] ******                       
           Location: line = 34, column = 5                                            
           Text: var curProc = host.currentProcess                                    

U kunt dit controleren door een stack-trace uit te voeren.

>>> Debug [DebuggableSample 34:5] >k                                                  
k                                                                                     
    ##  Function                         Pos    Source Snippet                        
-> [00] throwAndCatch                    034:05 (var curProc = host.currentProcess)   
   [01] outer                            066:05 (var foo = throwAndCatch())           
   [02] outermost                        074:05 (var result = outer())                

Hier kunt u de waarde van variabelen onderzoeken.

>>> Debug [DebuggableSample 34:5] >??someObj                
??someObj                                                   
someObj          : {...}                                    
    __proto__        : {...}                                
    a                : 0x63                                 
    b                : {...}                                
>>> Debug [DebuggableSample 34:5] >??someObj.b              
??someObj.b                                                 
someObj.b        : {...}                                    
    __proto__        : {...}                                
    c                : 0x20                                 
    d                : Hello World                          

Laten we een onderbrekingspunt instellen op de huidige coderegel en zien welke onderbrekingspunten er nu zijn ingesteld.

>>> Debug [DebuggableSample 34:5] >bpc                      
bpc                                                         
Breakpoint 1 set at 34:5                                    
>>> Debug [DebuggableSample 34:5] >bl                       
bl                                                          
      Id State    Pos                                       
       1 enabled  34:5                                      

Vanaf hier schakelen we de toetredingsgebeurtenis (entry event) uit met behulp van de sxd script debugger-opdracht.

>>> Debug [DebuggableSample 34:5] >sxd en                                                                              
sxd en                                                                                                                 
Event filter 'en' is now inactive                                                                                      

Laat het script gewoon tot het einde doorgaan.

>>> Debug [DebuggableSample 34:5] >g                                                                                   
g                                                                                                                      
This is a fun test                                                                                                     
Of the script debugger                                                                                                 
foo.a = 99                                                                                                             
Caught and returned!                                                                                                   
Test                                                                                                                   
...

Voer de scriptmethode opnieuw uit en observeer dat het onderbrekingspunt wordt bereikt.

0:000> dx @$scriptContents.outermost()                                                
inside outer!                                                                         
>>> ****** SCRIPT BREAK DebuggableSample [Breakpoint 1] ******                        
           Location: line = 34, column = 5                                            
           Text: var curProc = host.currentProcess                                    

De aanroepstack weergeven.

>>> Debug [DebuggableSample 34:5] >k                                                  
k                                                                                     
    ##  Function                         Pos    Source Snippet                        
-> [00] throwAndCatch                    034:05 (var curProc = host.currentProcess)   
   [01] outer                            066:05 (var foo = throwAndCatch())           
   [02] outermost                        074:05 (var result = outer())                

Op dit moment willen we stoppen met het opsporen van fouten in dit script, dus we ontkoppelen het.

>>> Debug [DebuggableSample 34:5] >.detach                  
.detach                                                     
Debugger has been detached from script!                     

Typ vervolgens q om af te sluiten.

q                                                           
This is a fun test                                          
Of the script debugger                                      
foo.a = 99                                                  
Caught and returned!                                        
Test                                                        

Wanneer u de functie opnieuw uitvoert, zal deze niet meer in de debugger onderbreken.

0:007> dx @$scriptContents.outermost()
inside outer!
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test

JavaScript in VS Code - IntelliSense toevoegen

Als u wilt werken met de gegevensmodelobjecten voor foutopsporingsprogramma's in VS Code, kunt u een definitiebestand gebruiken dat beschikbaar is in de Windows Development Kits. Het IntelliSense-definitiebestand biedt ondersteuning voor alle object-API's van het host.*-foutopsporingsprogramma. Als u de kit in de standaardmap op een 64-bits pc hebt geïnstalleerd, bevindt deze zich hier:

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\JsProvider.d.ts

Het IntelliSense-definitiebestand gebruiken in VS Code:

  1. Zoek het definitiebestand - JSProvider.d.ts

  2. Kopieer het definitiebestand naar dezelfde map als uw script.

  3. Voeg /// <reference path="JSProvider.d.ts" /> toe aan het begin van het JavaScript-scriptbestand.

Met deze verwijzing in uw JavaScript-bestand geeft VS Code u automatisch IntelliSense op de host-API's van JSProvider, naast de structuren in uw script. Typ bijvoorbeeld 'host'. en u ziet IntelliSense voor alle beschikbare foutopsporingsmodel-API's.

JavaScript-resources

Hier volgen JavaScript-resources die nuttig kunnen zijn bij het ontwikkelen van JavaScript-foutopsporingsextensies.

Zie ook

Voorbeeldscripts voor javaScript-foutopsporingsprogramma's

Systeemeigen objecten in JavaScript-extensies