Megosztás a következőn keresztül:


JavaScript-hibakereső szkriptelése

Ez a témakör azt ismerteti, hogyan hozhat létre javascriptet olyan szkriptek létrehozására, amelyek megértik a hibakereső objektumokat, és kiterjesztik és testre szabják a hibakereső képességeit.

A JavaScript Hibakereső szkriptjének áttekintése

A szkriptszolgáltatók összekötik a szkriptelési nyelvet a hibakereső belső objektummodelljével. A JavaScript hibakereső szkriptszolgáltató lehetővé teszi a JavaScript használatát a hibakeresővel.

Amikor egy JavaScript a .scriptload paranccsal töltődik be, a szkript gyökérkódja végrehajtásra kerül, a szkriptben található nevek a hibakereső (dx Debugger) gyökérnévterébe lesznek hidalva, és a szkript a memóriában marad, amíg ki nem üríti, és az objektumokra mutató összes hivatkozás ki nem kerül. A szkript új függvényeket biztosíthat a hibakereső kifejezés-kiértékelőjének, módosíthatja a hibakereső objektummodelljét, vagy vizualizációként ugyanúgy működhet, mint egy NatVis-vizualizáció.

Ez a témakör a JavaScript hibakereső szkriptek használatával elvégezhető műveletek némelyikét ismerteti.

Ez a két témakör további információt nyújt a JavaScript hibakeresőben való használatáról.

JavaScript-hibakereső példaszkriptjei

Natív objektumok JavaScript-bővítményekben

JavaScript-szkriptelési videó

Töredezettségmentesítési eszközök #170 – Andy és Bill bemutatják a JavaScript bővíthetőségét és szkriptelési képességeit a hibakeresőben.

A Hibakereső JavaScript-szolgáltatója

A hibakeresőhöz tartozó JavaScript-szolgáltató teljes mértékben kihasználja a legújabb ECMAScript6 objektum- és osztályfejlesztéseket. További információ: ECMAScript 6 – Új funkciók: Áttekintés és Összehasonlítás.

JsProvider.dll

JsProvider.dll a JavaScript-szolgáltató, amely betöltődik a JavaScript Hibakereső szkriptek támogatásához.

Követelmények

A JavaScript Debugger Scripting úgy lett kialakítva, hogy a Windows összes támogatott verziójával működjön.

A JavaScript-szkriptszolgáltató betöltése

A .script parancsok bármelyikének használata előtt be kell tölteni egy szkriptszolgáltatót. A .scriptproviders paranccsal ellenőrizze, hogy a JavaScript-szolgáltató be van-e töltve.

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

JavaScript metaparancsok

A JavaScript Debugger Scripting használatához az alábbi parancsok érhetők el.

Követelmények

A .script parancsok bármelyikének használata előtt be kell tölteni egy szkriptszolgáltatót. A .scriptproviders paranccsal ellenőrizze, hogy a JavaScript-szolgáltató be van-e töltve.

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

.scriptproviders (Szkriptszolgáltatók listázása)

A .scriptproviders parancs felsorolja az összes szkriptnyelvet, amelyet jelenleg a hibakereső és a bővítmény értelmez, amely alatt regisztrálva vannak.

Az alábbi példában a JavaScript- és NatVis-szolgáltatók töltődnek be.

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

Bármely ".NatVis" végződésű fájlt NatVis-szkriptként értjük, és bármely ".js" végződésű fájlt JavaScript-szkriptként értelmezzük. Bármelyik szkripttípus betölthető a .scriptload paranccsal.

További információ: .scriptproviders (Szkriptszolgáltatók listázása)

.scriptload (Szkript betöltése)

A .scriptload parancs betölt egy szkriptet, és végrehajtja egy szkript gyökérkódját és az inicializálásScript-függvényt . Ha a szkript kezdeti betöltése és végrehajtása során hiba lép fel, a hibák megjelennek a konzolon. Az alábbi parancs a TestScript.jssikeres betöltését mutatja be.

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

A szkript által végzett objektummodell-manipulációk mindaddig érvényben maradnak, amíg a szkriptet később ki nem ürítik, vagy más tartalommal újra nem futtatják.

További információ: .scriptload (Load Script)

.scriptrun

A .scriptrun parancs betölt egy szkriptet, végrehajtja a szkript gyökérkódját, az inicializálja aScriptet és az invokeScript függvényt. Ha a szkript kezdeti betöltése és végrehajtása során hiba lép fel, a hibák megjelennek a konzolon.

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

A szkript által végzett hibakereső objektummodell-manipulációk mindaddig érvényben maradnak, amíg a szkriptet később ki nem ürítik, vagy újra nem futtatják más tartalommal.

További információ: .scriptrun (Run Script).

.scriptunload (Szkript eltávolítása)

A .scriptunload parancs eltávolít egy betöltött szkriptet, és meghívja az uninitializeScript függvényt . Szkript eltávolításához használja az alábbi parancsszintaxist

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

További információt a .scriptunload (Szkript eltávolítása) című témakörben talál.

.scriptlist (Betöltött szkriptek listázása)

A .scriptlist parancs felsorolja azokat a szkripteket, amelyeket a .scriptload vagy a .scriptrun paranccsal töltöttek be. Ha a TestScript betöltése sikeresen megtörtént a .scriptload használatával, a .scriptlist parancs megjeleníti a betöltött szkript nevét.

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

További információ: .scriptlist (List Loaded Scripts).

A JavaScript Hibakereső szkriptelésének első lépései

HelloWorld példaszkript

Ez a szakasz bemutatja, hogyan hozhat létre és hajthat végre egy egyszerű JavaScript hibakereső szkriptet, amely kinyomtatja a Hello World parancsot.

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

A jegyzettömbhöz hasonló szövegszerkesztővel hozzon létre egy HelloWorld.js nevű szövegfájlt, amely tartalmazza a fent látható JavaScript-kódot.

A .scriptload paranccsal töltse be és hajtsa végre a szkriptet. Mivel az initializeScript függvénynevet használtuk, a program a szkript betöltésekor futtatja a függvény kódját.

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

A szkript betöltése után további funkciók érhetők el a hibakeresőben. A dx (NatVis-kifejezés megjelenítése) paranccsal megjelenítheti a Debugger.State.Scripts parancsot annak megtekintéséhez, hogy a szkript már rezidens.

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

A következő példában egy elnevezett függvényt adunk hozzá és hívunk meg.

Két érték hozzáadása példaszkript

Ez a szakasz azt ismerteti, hogyan hozhat létre és hajthat végre egy egyszerű JavaScript hibakereső szkriptet, amely hozzáadja a bemenetet, és két számot ad hozzá.

Ez az egyszerű szkript egyetlen függvényt biztosít, az addTwoValues függvényt.

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

Szövegszerkesztő, például Jegyzettömb használata egy FirstSampleFunction.js nevű szövegfájl létrehozásához

A .scriptload paranccsal töltse be a szkriptet.

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

A szkript betöltése után további funkciók érhetők el a hibakeresőben. A dx (NatVis-kifejezés megjelenítése) paranccsal megjelenítheti a Debugger.State.Scripts parancsot annak megtekintéséhez, hogy a szkript már rezidens.

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

A FirstSampleFunction lehetőséget választva megtekintheti, hogy milyen függvényeket biztosít.

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

Ha egy kicsit kényelmesebbé szeretné tenni a szkript használatát, rendeljen hozzá egy változót a hibakeresőben a szkript tartalmának tárolásához a dx paranccsal.

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

Az addTwoValues függvény meghívásához használja a dx kifejezésértékelőt.

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

A szkriptek használatához használhatja a beépített @$scriptContents aliast is. A @$scriptContents alias egyesíti az összes betöltött szkript teljes tartalmát.

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

Ha végzett a szkripttel, a .scriptunload paranccsal távolítsa el a szkriptet.

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

Hibakereső parancsautomatizálás

Ez a szakasz azt ismerteti, hogyan hozhat létre és hajthat végre egy egyszerű JavaScript hibakereső szkriptet, amely automatizálja az u (Összeszereletlen) parancs küldését . A minta azt is bemutatja, hogyan gyűjtheti össze és jelenítheti meg a parancs kimenetét egy ciklusban.

Ez a szkript egyetlen függvényt biztosít, a RunCommands() függvényt.

// 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");

}

Szövegszerkesztő, például Jegyzettömb használata egy RunCommands.js nevű szövegfájl létrehozásához

A .scriptload paranccsal töltse be a RunCommands szkriptet.

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

A szkript betöltése után további funkciók érhetők el a hibakeresőben. A dx (NatVis-kifejezés megjelenítése) paranccsal megjelenítheti a Debugger.State.Scripts.RunCommands parancsot annak megtekintéséhez, hogy a szkript már rezidens.

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]

A dx paranccsal hívja meg a RunCommands függvényt a RunCommands szkriptben.

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

Speciális JavaScript Hibakereső függvények

Egy JavaScript-szkriptben számos speciális függvény található, amelyeket maga a szkriptszolgáltató hív meg.

inicializálScript

Amikor egy JavaScript-szkript betöltődik és végrehajtja, több lépésből áll, mielőtt a szkript változói, függvényei és egyéb objektumai hatással lesznek a hibakereső objektummodellére.

  • A szkript be lesz töltve a memóriába, és elemezve lesz.
  • A szkript gyökérkódja végrehajtásra kerül.
  • Ha a szkriptnek van egy inicializálásScript nevű metódusa, akkor a metódust meghívja.
  • Az initializeScript visszatérési értéke határozza meg, hogyan módosítható automatikusan a hibakereső objektummodellje.
  • A szkriptben szereplő nevek összekapcsolódnak a hibakereső névterével.

Ahogy már említettük, az initializeScript a szkript fő kódjának végrehajtása után azonnal meg lesz hívva. Feladata a regisztrációs objektumok JavaScript-tömbjének visszaadása a szolgáltatónak, amely jelzi a hibakereső objektummodelljének módosítását.

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

Az invokeScript metódus az elsődleges szkriptmetódus, amely a .scriptload és a .scriptrun futtatásakor lesz meghívva.

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

Az uninitializeScript metódus az initializeScript metódus viselkedése ellentétes. A parancsprogram akkor hívható meg, ha egy szkript nincs összekapcsolva, és készen áll a kiürítésre. Feladata, hogy visszavonja az objektummodell azon módosításait, amelyeket a szkript a végrehajtás során imperatív módon végzett, és/vagy megsemmisítse a szkript által gyorsítótárazott objektumokat.

Ha egy szkript nem végez imperatív módosításokat az objektummodellen, és nem gyorsítótárazza az eredményeket, nem kell uninitializeScript metódussal rendelkeznie. A szolgáltató automatikusan visszavonja az objektummodellnek az inicializálásScript visszatérési értéke által jelzett módosításait. Az ilyen módosításokhoz nincs szükség explicit uninitializeScript metódusra.

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");
}

A szkriptparancsok által meghívott függvények összegzése

Ez a táblázat összefoglalja, hogy a szkriptparancsok mely függvényeket hívják meg

Parancs .scriptload .scriptrun (szkript futtatása) .scriptunload (Szkript eltávolítása)
gyökér igen igen
inicializálásSkript igen igen
invokeScript igen
uninitializeScript igen

Ezzel a mintakóddal megtekintheti, hogy a rendszer mikor hívja meg az egyes függvényeket a szkript betöltése, végrehajtása és eltávolítása során.

// 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");
}

Hibakereső vizualizáció létrehozása JavaScriptben

Az egyéni vizualizációs fájlok lehetővé teszik az adatok csoportosítását és rendszerezését egy olyan vizualizációs struktúrában, amely jobban tükrözi az adatkapcsolatokat és a tartalmat. A JavaScript hibakereső bővítményekkel olyan hibakereső vizualizációkat írhat, amelyek a NatVishez hasonlóan működnek. Ez egy JavaScript-prototípus-objektum (vagy ES6-osztály) megírásával érhető el, amely egy adott adattípus vizualizációjaként működik. További információ a NatVisről és a hibakeresőről: dx (NatVis-kifejezés megjelenítése).

Példaosztály – Simple1DArray

Vegyünk egy példát egy egydimenziós tömböt képviselő C++ osztályra. Ez az osztály két tagból áll, m_size, amely a tömb teljes mérete, és m_pValues, amely a memória több ints elemére mutató mutató, amely megegyezik a m_size mezővel.

class Simple1DArray
{
private:

    ULONG64 m_size;
    int *m_pValues;
};

A dx paranccsal megvizsgálhatjuk az alapértelmezett adatszerkezet-renderelést.

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

JavaScript-vizualizáció

Ennek a típusnak a vizualizációja érdekében létre kell hoznunk egy prototípus (vagy ES6) osztályt, amely rendelkezik a hibakereső által megjelenítendő összes mezővel és tulajdonsággal. Azt is meg kell, hogy az initializeScript metódus egy objektumot adjon vissza, amely arra utasítja a JavaScript-szolgáltatót, hogy csatolja a prototípust vizualizációként az adott típushoz.

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")];
}

Mentse a szkriptet egy arrayVisualizer.jsnevű fájlba.

A JavaScript-szolgáltató betöltéséhez használja a .load (Load Extension DLL) parancsot.

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

A .scriptload használatával töltse be a tömbábrázoló szkriptet.

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

Most, amikor a dx parancsot használja, a szkriptábrázoló megjeleníti a tömbtartalom sorait.

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

Emellett ez a JavaScript-vizualizáció LINQ-funkciókat is biztosít, például a Kiválasztás funkciót.

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

Mi befolyásolja a vizualizációt?

Az a prototípus vagy osztály, amely egy host.typeSignatureRegistration objektum inicializálásiscriptből való visszatérésével készíti el a natív típus vizualizációját, a JavaScriptben lévő összes tulajdonságot és metódust hozzáadja a natív típushoz. Emellett a következő szemantikák érvényesek:

  • A vizualizációban minden olyan név elérhető lesz, amely nem két aláhúzásjellel (__) kezdődik.

  • A szabványos JavaScript-objektumok részét képező vagy a JavaScript-szolgáltató által létrehozott protokollok részét képező nevek nem jelennek meg a vizualizációban.

  • Egy objektum a [Symbol.iterator] támogatásával iterizálhatóvá tehető.

  • Egy objektum egy több függvényből álló egyéni protokoll támogatásával indexelhetővé tehető: getDimensionality, getValueAt és opcionálisan setValueAt.

Natív és JavaScript objektumhíd

A JavaScript és a hibakereső objektummodellje közötti híd kétirányú. A natív objektumok átadhatók a JavaScriptbe, a JavaScript-objektumok pedig átadhatók a hibakereső kifejezés-kiértékelőjének. Erre példaként vegye figyelembe a következő metódus hozzáadását a szkriptben:

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

Ez a módszer most már használható a fenti LINQ-lekérdezésben. Először betöltjük a JavaScript-vizualizációt.

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

Ezután soron belül használhatjuk a multiplyBySeven függvényt, ahogy alább látható.

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

Feltételes töréspontok JavaScripttel

A JavaScript használatával kiegészítő feldolgozást végezhet egy töréspont elérése után. A szkript például használható más futtatási időértékek vizsgálatára, majd annak meghatározására, hogy szeretné-e automatikusan folytatni a kódvégrehajtást vagy leállítani, és további manuális hibakeresést végezni.

A töréspontok kezelésével kapcsolatos általános információkért lásd a töréspontok vezérlésének módszereit.

DebugHandler.js példa töréspont-feldolgozási szkriptje

Ez a példa kiértékeli a jegyzettömb megnyitott és mentési párbeszédpaneljét: jegyzettömb! ShowOpenSaveDialog. Ez a szkript kiértékeli a pszCaption változót annak megállapításához, hogy az aktuális párbeszédpanel megnyitási párbeszédpanel-e vagy mentési párbeszédpanel. Nyitott párbeszédpanel esetén a kódvégrehajtás folytatódik. Ha ez egy mentési párbeszédpanel, a kódvégrehajtás leáll, és a hibakereső be fog törni.

 // 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");
    }
  }

Ez a parancs beállít egy töréspontot a jegyzettömbön! ShowOpenSaveDialog, és a fenti szkriptet futtatja, amikor a töréspontot eléri.

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

Ezután, amikor a Fájl > mentése lehetőséget választja a jegyzettömbben, a szkript fut, a g parancs nem lesz elküldve, és a kódfuttatás megszakad.

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

64 bites értékek használata JavaScript-bővítményekben

Ez a szakasz a JavaScript hibakereső bővítménybe átadott 64 bites értékek viselkedését ismerteti. Ez a probléma azért merül fel, mert a JavaScript csak 53 bites számok tárolására képes.

64 bites és JavaScript 53 bites tárterület

A JavaScriptbe átadott ordinális értékek általában JavaScript-számokként vannak megadva. Ezzel az a probléma, hogy a JavaScript-számok 64 bites dupla pontosságú lebegőpontos értékek. Az 53 bitesnél nagyobb sorszámok a JavaScriptbe való belépéskor elveszítik a pontosságukat. Ez problémát jelent a 64 bites mutatók és az egyéb 64 bites sorszámértékek esetében, amelyek a legmagasabb bájtokban lévő jelzőkkel rendelkezhetnek. Ennek kezeléséhez a JavaScriptet beíró 64 bites natív érték (akár natív kódból, akár adatmodellből) kódtártípusként van beadva – nem JavaScript-számként. Ez a kódtártípus a numerikus pontosság elvesztése nélkül visszavezeti a natív kódra.

Automatikus átalakítás

A 64 bites ordinals értékeket kezelő könyvtártípus támogatja a szabványos JavaScript valueOf átalakítást. Ha az objektumot olyan matematikai műveletben vagy más szerkezetben használják, amely értékkonvertálást igényel, akkor az automatikusan JavaScript-számmá alakul. Ha a pontosságvesztés bekövetkezne (az érték több mint 53 bites pontosságot használ), a JavaScript-szolgáltató kivételt küld.

Vegye figyelembe, hogy ha bitenkénti operátorokat használ a JavaScriptben, akkor az ordinális pontosságot tovább korlátozzák a 32 bitre.

Ez a mintakód két számot összegz, és a 64 bites értékek konvertálásának tesztelésére szolgál.

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);
}

Szövegszerkesztő, például Jegyzettömb használata egy PlayWith64BitValues.js nevű szövegfájl létrehozásához

A .scriptload paranccsal töltse be a szkriptet.

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

Ha egy kicsit kényelmesebbé szeretné tenni a szkript használatát, rendeljen hozzá egy változót a hibakeresőben a szkript tartalmának tárolásához a dx paranccsal.

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

Az addTwoValues függvény meghívásához használja a dx kifejezésértékelőt.

Először a 2^53 =9007199254740992 (Hex 0x20000000000000) értéket számítjuk ki.

Először a (2^53) – 2 értéket fogjuk használni, és látni fogjuk, hogy az összeg helyes értékét adja vissza.

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

Ezután kiszámítjuk a (2^53) -1 =9007199254740991. Ez azt a hibát adja vissza, amely azt jelzi, hogy a konvertálási folyamat elveszíti a pontosságát, ezért ez a legnagyobb érték, amely a JavaScript-kódban használható összeg metódussal használható.

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

64 bites értékeket átadó adatmodell-metódus meghívása. Itt nincs pontosságvesztés.

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

Összehasonlítás

A 64 bites kódtár típusa JavaScript-objektum, és nem értéktípus, például JavaScript-szám. Ez hatással van az összehasonlítási műveletekre. Egy objektum egyenlősége (==) általában azt jelzi, hogy az operandusok ugyanarra az objektumra hivatkoznak, nem pedig ugyanarra az értékre. A JavaScript-szolgáltató ezt azzal enyhíti, hogy 64 bites értékekre mutató élő hivatkozásokat követ, és ugyanazt a "nem módosítható" objektumot adja vissza a nem összegyűjtött 64 bites értékekhez. Ez azt jelenti, hogy összehasonlítás céljából a következők történnek.

// 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");

Szövegszerkesztő, például Jegyzettömb használata egy ComparisonWith64BitValues.js nevű szövegfájl létrehozásához

A .scriptload paranccsal töltse be a szkriptet.

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

Ha egy kicsit kényelmesebbé szeretné tenni a szkript használatát, rendeljen hozzá egy változót a hibakeresőben a szkript tartalmának tárolásához a dx paranccsal.

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

Először a (2^53) – 2 értéket fogjuk használni, és látni fogjuk, hogy a várt értékeket adja vissza.

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

A 42-es számot is megpróbáljuk elsőként ellenőrizni, hogy az összehasonlító operátor megfelelően működik-e.

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

Ezután kiszámítjuk a (2^53) -1 =9007199254740991. Ez az érték azt a hibát adja vissza, amely azt jelzi, hogy a konvertálási folyamat elveszíti a pontosságát, ezért ez a legnagyobb érték, amely a JavaScript-kód összehasonlító operátoraival használható.

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

A pontosság fenntartása a műveletekben

Annak érdekében, hogy a hibakereső bővítmények megőrizhessék a pontosságot, matematikai függvények halmaza a 64 bites kódtártípusra lesz kivetítve. Ha a bővítménynek 53 bites pontosságra van szüksége a bejövő 64 bites értékekhez, a standard operátorok helyett a következő módszereket kell használni:

Metódus neve Aláírás Leírás
asNumber .asNumber() A 64 bites értéket JavaScript-számmá alakítja. Ha a pontosság romlik, **KIVÉTELT AD**
convertToNumber (számra alakít) .convertToNumber() A 64 bites értéket JavaScript-számmá alakítja. Ha pontosságvesztés történik, **NINCS KIVÉTEL**
alsóRészLekérdező .getLowPart() A 64 bites érték alsó 32 bites értékeit JavaScript-számmá alakítja
getHighPart .getHighPart() A 64 bites érték felső 32 bitjét JavaScript számra alakítja
hozzáad .add(value) Hozzáad egy értéket a 64 bites értékhez, és visszaadja az eredményt
kivon .subtract(value) Kivon egy értéket a 64 bites értékből, és visszaadja az eredményt
szoroz .szoroz(érték) Megszorozza a 64 bites értéket a megadott értékkel, és visszaadja az eredményt
oszt .divide(value) Osztja a 64 bites értéket a megadott értékkel, és visszaadja az eredményt
bitenkénti és .bitwiseAnd(érték) Kiszámítja a bitenkénti és a 64 bites értéket a megadott értékkel, és visszaadja az eredményt
bitwiseOr .bitwiseOr(érték) Kiszámítja a bitenkénti vagy a 64 bites értéket a megadott értékkel, és visszaadja az eredményt
bitwiseXor .bitwiseXor(érték) Kiszámítja a 64 bites érték bitenkénti xorját a megadott értékkel, és visszaadja az eredményt
bitwiseShiftLeft .bitwiseShiftLeft(érték) Az adott értékkel balra eltolja a 64 bites értéket, és visszaadja az eredményt.
bitwiseShiftRight .bitwiseShiftRight(érték) A 64 bites értéket a megadott mértékkel jobbra tolja, és visszaadja az eredményt.
toString .toString([radix]) A 64 bites értéket átalakítja egy megjelenítési sztringgé az alapértelmezett radixban (vagy az opcionálisan megadott radixban)

Ez a módszer is elérhető.

Metódus neve Aláírás Leírás
compareTo .compareTo(érték) Összehasonlítja a 64 bites értéket egy másik 64 bites értékkel.

JavaScript-hibakeresés

Ez a szakasz bemutatja, hogyan használhatja a hibakereső szkript hibakeresési képességeit. A hibakereső integráltan támogatja a JavaScript-szkriptek hibakeresését a .scriptdebug (Debug JavaScript) paranccsal.

Megjegyzés:

Ha JavaScript-hibakeresést szeretne használni a WinDbg használatával, futtassa a hibakeresőt rendszergazdaként.

Ezzel a mintakóddal feltárhatja a JavaScript hibakeresését. Ehhez az útmutatóhoz elnevezzük DebuggableSample.js, és a C:\MyScripts könyvtárba mentjük.

"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
    //
}

Töltse be a mintaszkriptet.

.scriptload C:\MyScripts\DebuggableSample.js

Kezdje el aktívan a szkript hibakeresését a .scriptdebug paranccsal.

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

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

Miután megjelenik a prompt >>> Debug [DebuggableSample <No Position>] > és bemeneti kérés érkezik, belép a szkript hibakeresőbe.

A .help paranccsal megjelenítheti a parancsok listáját a JavaScript hibakeresési környezetben.

>>> 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

Az sx szkript hibakereső parancsával megtekintheti a csapdába ejteni kívánt események listáját.

>>> 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     

Használja az sxe szkript hibakereső parancsot a belépéskor történő megszakítás bekapcsolásához, hogy a szkript azonnal bekerüljön a szkript hibakeresőjébe, amint bármely benne lévő kód végrehajtásra kerül.

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

Lépjen ki a szkript hibakeresőből, majd végrehajtunk egy függvényhívást a szkriptben, ami a hibakeresőben fog elakadni.

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

Ezen a ponton visszatér a normál hibakeresőhöz. Futtassa a következő parancsot a szkript meghívásához.

dx @$scriptContents.outermost()

Most visszakerül a szkript hibakeresőjébe, és megállítva van a legkülső JavaScript függvény első soránál.

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

>>> Debug [DebuggableSample 73:5] >                         

A hibakeresőnél történő megszakításon túl láthatók a sor (73) és az oszlop (5) információi, ahol a megszakítás történt, valamint a forráskód vonatkozó kódrészlete: var x = 99.

Tegyünk meg néhány lépést, és jussunk el egy másik helyre a szkriptben.

    p
    t
    p
    t
    p
    p

Ezen a ponton be kell lépned a throwAndCatch metódusba a 34-es sorban.

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

Ezt egy veremkövetés végrehajtásával ellenőrizheti.

>>> 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())                

Innen megvizsgálhatja a változók értékét.

>>> 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                          

Állítsunk be egy töréspontot az aktuális kódsoron, és nézzük meg, hogy milyen töréspontok lettek beállítva.

>>> 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                                      

Innen letiltjuk a bejegyzés (en) eseményt az sxd szkript hibakereső parancsával.

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

Ezután csak menjen, és hagyja, hogy a szkript a végéig folytatódjon.

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

Futtassa újra a szkriptet, és figyelje a töréspont eltalálását.

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

A hívásverem megjelenítése.

>>> 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())                

Ezen a ponton le szeretnénk állítani a szkript hibakeresését, ezért leválasztunk róla.

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

Ezután írja be a q parancsot a kilépéshez.

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

A függvény ismételt végrehajtása többé nem lép be a hibakeresőbe.

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

JavaScript a VS Code-ban – IntelliSense hozzáadása

Ha a VS Code hibakereső adatmodell-objektumaival szeretne dolgozni, használhat egy definíciós fájlt, amely elérhető a Windows fejlesztői készleteiben. Az IntelliSense definíciós fájl támogatást nyújt az összes host.* hibakereső objektumhoz tartozó API-hoz. Ha a készletet az alapértelmezett könyvtárba telepítette egy 64 bites PC-n, a következő helyen található:

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

Az IntelliSense definíciós fájl használata a VS Code-ban:

  1. Keresse meg a definíciós fájlt – JSProvider.d.ts

  2. Másolja a definíciós fájlt a szkripttel megegyező mappába.

  3. Adja hozzá /// <reference path="JSProvider.d.ts" /> a JavaScript-szkriptfájl elejéhez.

A JavaScript-fájlban található hivatkozással a VS Code automatikusan IntelliSense-t ad a JSProvider által biztosított host API-khoz a szkripted struktúrái mellett. Írja be például a "gazdagép" kifejezést. és az összes elérhető hibakereső modell API-hoz az IntelliSense megjelenik.

JavaScript-erőforrások

A következő JavaScript-erőforrások hasznosak lehetnek a JavaScript hibakeresési bővítmények fejlesztése során.

Lásd még:

JavaScript-hibakereső példaszkriptjei

Natív objektumok JavaScript-bővítményekben