Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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.
- .scriptproviders (Szkriptszolgáltatók listázása)
- .scriptload (Szkript betöltése)
- .scriptunload (Szkript eltávolítása)
- .scriptrun (szkript futtatása)
- .scriptlist (Betöltött szkriptek listázása)
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:
Keresse meg a definíciós fájlt – JSProvider.d.ts
Másolja a definíciós fájlt a szkripttel megegyező mappába.
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.