Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här avsnittet beskriver hur du använder JavaScript för att skapa skript som förstår felsökningsobjekt och utökar och anpassar funktionerna i felsökningsprogrammet.
Översikt över Skript för JavaScript-felsökningsprogram
Skriptprovidrar överbryggar ett skriptspråk till felsökarens interna objektmodell. JavaScript-skriptprovidern för felsökning tillåter användning av JavaScript med felsökningsprogrammet.
När ett JavaScript läses in via kommandot .scriptload körs rotkoden för skriptet, namnen som finns i skriptet bryggs till rotnamnområdet för felsökningsprogrammet (dx Debugger) och skriptet förblir kvar i minnet tills det tas bort och alla referenser till dess objekt släpps. Skriptet kan ge nya funktioner till felsökarens uttrycksutvärderare, ändra objektmodellen för felsökningsprogrammet eller fungera som visualiserare på ungefär samma sätt som en NatVis-visualiserare.
I det här avsnittet beskrivs en del av vad du kan göra med JavaScript-felsökningsskript.
De här två avsnitten innehåller ytterligare information om hur du arbetar med JavaScript i felsökningsprogrammet.
Exempelskript för JavaScript-felsökningsprogram
Inbyggda objekt i JavaScript-tillägg
JavaScript-skriptvideo
Defrag Tools #170 – Andy och Bill demonstrerar JavaScript-utökningsbarhet och skriptfunktioner i felsökningsprogrammet.
JavaScript-providern för felsökningsprogrammet
JavaScript-providern som ingår i felsökningsprogrammet drar full nytta av de senaste förbättringarna av ECMAScript6-objektet och -klassen. Mer information finns i ECMAScript 6 – Nya funktioner: Översikt och jämförelse.
JsProvider.dll
JsProvider.dll är JavaScript-leverantören som läses in för att stödja JavaScript Debugger Scripting.
Requirements
JavaScript Debugger Scripting är utformat för att fungera med alla versioner av Windows som stöds.
Laddar JavaScript-skriptleverantören
Innan du använder något av .script-kommandona behöver en skriptleverantör laddas in. Använd kommandot .scriptproviders för att bekräfta att JavaScript-providern har lästs in.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
Metakommandon för JavaScript-skript
Följande kommandon är tillgängliga för att använda JavaScript-felsökarskript.
- .scriptproviders (lista skriptleverantörer)
- .scriptload (Läs in skript)
- .scriptunload (Ta bort skript)
- .scriptrun (Kör skript)
- .scriptlist (Lista inlästa skript)
Requirements
Innan du använder något av .script-kommandona måste en skriptleverantör läsas in. Använd kommandot .scriptproviders för att bekräfta att JavaScript-providern har lästs in.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
.scriptproviders (listskriptleverantörer)
Kommandot .scriptproviders visar en lista över alla skriptspråk som för närvarande tolkas av felsökaren och tillägget som de är registrerade under.
I exemplet nedan laddas JavaScript- och NatVis-leverantörerna.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
Alla filer som slutar på ". NatVis" förstås som ett NatVis-skript och alla filer som slutar med ".js" förstås som ett JavaScript-skript. Båda typerna av skript kan läsas in med kommandot .scriptload.
Mer information finns i .scriptproviders (List Script Providers)
.scriptload (Läs in skript)
Kommandot .scriptload läser in ett skript och kör rotkoden för ett skript och funktionen initializeScript . Om det finns fel i den första inläsningen och körningen av skriptet visas felen i konsolen. Följande kommando visar den lyckade laddningen av TestScript.js.
0:000> .scriptload C:\WinDbg\Scripts\TestScript.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\TestScript.js'
Alla objektmodellmanipuleringar som görs av skriptet finns kvar tills skriptet därefter tas bort eller körs igen med annat innehåll.
Mer information finns i .scriptload (Load Script)
.scriptrun
Kommandot .scriptrun läser in ett skript, kör rotkoden för skriptet, initieraScript och invokeScript-funktionen . Om det finns fel i den första inläsningen och körningen av skriptet visas felen i konsolen.
0:000> .scriptrun C:\WinDbg\Scripts\helloWorld.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\helloWorld.js'
Hello World! We are in JavaScript!
Alla manipulationer av felsökningsobjektmodellen som görs av skriptet kommer att vara kvar tills skriptet därefter tas bort eller körs igen med annat innehåll.
Mer information finns i .scriptrun (Kör skript).
.scriptunload (Ta bort skript)
Kommandot .scriptunload tar bort ett inläst skript och anropar funktionen uninitializeScript . Använd följande kommandosyntax för att ta bort ett skript
0:000:x86> .scriptunload C:\WinDbg\Scripts\TestScript.js
JavaScript script unloaded from 'C:\WinDbg\Scripts\TestScript.js'
Mer information finns i .scriptunload (Ta bort skript).
.scriptlist (Lista inlästa skript)
Kommandot .scriptlist visar alla skript som har lästs in via kommandot .scriptload eller .scriptrun. Om TestScript har lästs in med hjälp av .scriptload visar kommandot .scriptlist namnet på det inlästa skriptet.
0:000> .scriptlist
Command Loaded Scripts:
JavaScript script from 'C:\WinDbg\Scripts\TestScript.js'
Mer information finns i .scriptlist (List Loaded Scripts).
Kom igång med Skript för JavaScript-felsökningsprogram
HelloWorld-exempelskript
I det här avsnittet beskrivs hur du skapar och kör ett enkelt JavaScript-felsökningsskript som skriver ut Hello World.
// WinDbg JavaScript sample
// Prints Hello World
function initializeScript()
{
host.diagnostics.debugLog("***> Hello World! \n");
}
Använd en textredigerare som Anteckningar för att skapa en textfil med namnet HelloWorld.js som innehåller JavaScript-koden som visas ovan.
Använd kommandot .scriptload för att läsa in och köra skriptet. Eftersom vi använde funktionsnamnet initializeScript körs koden i funktionen när skriptet läses in.
0:000> .scriptload c:\WinDbg\Scripts\HelloWorld.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\HelloWorld.js'
***> Hello World!
När skriptet har lästs in är ytterligare funktioner tillgängliga i felsökningsprogrammet. Använd kommandot dx (Display NatVis Expression) för att visa Debugger.State.Scripts för att se att vårt skript nu är bosatt.
0:000> dx Debugger.State.Scripts
Debugger.State.Scripts
HelloWorld
I nästa exempel lägger vi till och anropar en namngiven funktion.
Lägga till exempelskript för två värden
I det här avsnittet beskrivs hur du skapar och kör ett enkelt JavaScript-debuggerskript som tar indata och adderar två tal.
Det här enkla skriptet innehåller en enda funktion, addTwoValues.
// WinDbg JavaScript sample
// Adds two functions
function addTwoValues(a, b)
{
return a + b;
}
Använd en textredigerare som Anteckningar för att skapa en textfil med namnet FirstSampleFunction.js
Använd kommandot .scriptload för att läsa in skriptet.
0:000> .scriptload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'
När skriptet har lästs in är ytterligare funktioner tillgängliga i felsökningsprogrammet. Använd kommandot dx (Display NatVis Expression) för att visa Debugger.State.Scripts för att se att vårt skript nu är bosatt.
0:000> dx Debugger.State.Scripts
Debugger.State.Scripts
FirstSampleFunction
Vi kan välja FirstSampleFunction för att se vilka funktioner den tillhandahåller.
0:000> dx -r1 -v Debugger.State.Scripts.FirstSampleFunction.Contents
Debugger.State.Scripts.FirstSampleFunction.Contents : [object Object]
host : [object Object]
addTwoValues
...
Om du vill göra skriptet lite enklare att arbeta med tilldelar du en variabel i felsökningsprogrammet för att lagra innehållet i skriptet med hjälp av dx-kommandot.
0:000> dx @$myScript = Debugger.State.Scripts.FirstSampleFunction.Contents
Använd dx-uttrycksutvärderingen för att anropa funktionen addTwoValues.
0:000> dx @$myScript.addTwoValues(10, 41),d
@$myScript.addTwoValues(10, 41),d : 51
Du kan också använda @$scriptContents inbyggda alias för att arbeta med skripten. Aliaset @$scriptContents sammanfogar alla . Innehållet i alla skript som läses in.
0:001> dx @$scriptContents.addTwoValues(10, 40),d
@$scriptContents.addTwoValues(10, 40),d : 50
När du är klar med att arbeta med skriptet använder du kommandot .scriptunload för att ta bort skriptet.
0:000> .scriptunload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully unloaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'
Felsökningskommandoautomatisering
I det här avsnittet beskrivs hur du skapar och kör ett enkelt JavaScript-debuggerscript som automatiserar sändningen av u (Unassemble)-kommandot. Exemplet visar också hur du samlar in och visar kommandoutdata i en loop.
Det här skriptet innehåller en enda funktion, 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");
}
Använd en textredigerare som Anteckningar för att skapa en textfil med namnet RunCommands.js
Använd kommandot .scriptload för att läsa in RunCommands-skriptet.
0:000> .scriptload c:\WinDbg\Scripts\RunCommands.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\RunCommands.js'
När skriptet har lästs in är ytterligare funktioner tillgängliga i felsökningsprogrammet. Använd kommandot dx (Display NatVis Expression) för att visa Debugger.State.Scripts.RunCommands för att se att skriptet nu är bosatt.
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]
Använd dx-kommandot för att anropa funktionen RunCommands i RunCommands-skriptet.
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
Särskilda JavaScript-felsökningsfunktioner
Det finns flera specialfunktioner i ett JavaScript-skript som anropas av själva skriptprovidern.
initializeScript
När ett JavaScript-skript läses in och körs går det igenom en serie steg innan variabler, funktioner och andra objekt i skriptet påverkar felsökarens objektmodell.
- Skriptet läses in i minnet och parsas.
- Rotkoden i skriptet körs.
- Om skriptet har en metod som kallas initializeScript anropas den metoden.
- Returvärdet från initializeScript används för att fastställa hur objektmodellen för felsökningsprogrammet ska ändras automatiskt.
- Namnen i skriptet bryggs till felsökarens namnområde.
Som nämnts anropas initializeScript omedelbart efter att rotkoden för skriptet har körts. Dess jobb är att returnera en JavaScript-matris med registreringsobjekt till providern som anger hur du ändrar objektmodellen för felsökningsprogrammet.
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
Metoden invokeScript är den primära skriptmetoden och anropas när .scriptload och .scriptrun körs.
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
Metoden uninitializeScript är den beteendemässiga motsatsen till initializeScript. Det anropas när ett skript är olänkat och gör sig redo att avlasta. Dess uppgift är att ångra alla ändringar i objektmodellen som skriptet gjorde imperativt under körningen och/eller att förstöra alla objekt som skriptet cachelagrade.
Om ett skript varken utför imperativa manipuleringar av objektmodellen eller cachelagrar resultat behöver det inte ha någon uninitializeScript-metod. Ändringar i objektmodellen som utförs enligt returvärdet för initializeScript ångras automatiskt av providern. Sådana ändringar kräver ingen explicit uninitializeScript-metod.
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");
}
Sammanfattning av funktioner som anropas av skriptkommandon
Den här tabellen sammanfattar vilka funktioner som anropas av skriptkommandona
| Command | .scriptload | .scriptrun (Kör skript) | .scriptunload (Ta bort skript) |
|---|---|---|---|
| rot | Ja | Ja | |
| initializeScript | Ja | Ja | |
| invokeScript | Ja | ||
| uninitializeScript | Ja |
Använd den här exempelkoden för att se när varje funktion anropas när skriptet läses in, körs och tas bort.
// 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");
}
Skapa en felsökningsvisualiserare i JavaScript
Med anpassade visualiseringsfiler kan du gruppera och organisera data i en visualiseringsstruktur som bättre återspeglar datarelationerna och innehållet. Du kan använda JavaScript-felsökningstilläggen för att skriva felsökningsvisualiserare som fungerar på ett sätt som liknar NatVis. Detta görs genom redigering av ett JavaScript-prototypobjekt (eller en ES6-klass) som fungerar som visualiserare för en viss datatyp. Mer information om NatVis och felsökningsprogrammet finns i dx (Visa NatVis-uttryck).
Exempelklass – Simple1DArray
Tänk dig ett exempel på en C++-klass som representerar en endimensionell matris. Den här klassen har två medlemmar, m_size som är matrisens totala storlek och m_pValues som är en pekare till ett antal ints i minnet som är lika med det m_size fältet.
class Simple1DArray
{
private:
ULONG64 m_size;
int *m_pValues;
};
Vi kan använda dx-kommandot för att titta på standardåtergivningen av datastrukturen.
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
För att visualisera den här typen måste vi skapa en prototypklass (eller ES6) som har alla fält och egenskaper som vi vill att felsökningsprogrammet ska visa. Vi måste också låta metoden initializeScript returnera ett objekt som instruerar JavaScript-providern att länka vår prototyp som visualiserare för den angivna typen.
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")];
}
Spara skriptet i en fil med namnet arrayVisualizer.js.
Använd kommandot .load (Load Extension DLL) för att läsa in JavaScript-providern.
0:000> .load C:\ScriptProviders\jsprovider.dll
Använd .scriptload för att läsa in matrisvisualiserarskriptet.
0:000> .scriptload c:\WinDbg\Scripts\arrayVisualizer.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\arrayVisualizer.js'
Nu när dx-kommandot används visar skriptvisualiseraren rader med matrisinnehåll.
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
Dessutom tillhandahåller den här JavaScript-visualiseringen LINQ-funktioner, till exempel Välj.
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
Vad påverkar visualiseringen
En prototyp eller klass som görs till visualiserare för en intern typ via en retur av ett host.typeSignatureRegistration-objekt från initializeScript kommer att ha alla egenskaper och metoder i JavaScript tillagt till den inbyggda typen. Dessutom gäller följande semantik:
Alla namn som inte börjar med två understreck (__) kommer att vara tillgängliga i visualiseringen.
Namn som ingår i JavaScript-standardobjekt eller ingår i protokoll som JavaScript-providern skapar visas inte i visualiseringen.
Ett objekt kan göras iterbart via stöd för [Symbol.iterator].
Ett objekt kan göras indexerbart via stöd för ett anpassat protokoll som består av flera funktioner: getDimensionality, getValueAt och valfritt setValueAt.
Inbyggd objektbrygga och JavaScript-objektbrygga
Bryggan mellan JavaScript och objektmodellen för felsökningsprogrammet är dubbelriktad. Inbyggda objekt kan skickas till JavaScript och JavaScript-objekt kan skickas till felsökarens uttrycksutvärdering. Som ett exempel på detta bör du överväga att lägga till följande metod i skriptet:
function multiplyBySeven(val)
{
return val * 7;
}
Den här metoden kan nu användas i linq-exempelfrågan ovan. Först läser vi in JavaScript-visualiseringen.
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
Sedan kan vi använda funktionen multiplyBySeven direkt enligt nedan.
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
Villkorsstyrda brytpunkter med JavaScript
Du kan använda JavaScript för att utföra kompletterande bearbetning när en brytpunkt har nåtts. Skript kan till exempel användas för att undersöka andra körningstidsvärden och sedan avgöra om du vill fortsätta kodkörningen automatiskt eller stoppa och utföra ytterligare manuell felsökning.
Allmän information om hur du arbetar med brytpunkter finns i Metoder för att kontrollera brytpunkter.
DebugHandler.js exempel på skript för brytpunktsbearbetning
Det här exemplet utvärderar anteckningsblockets öppna och sparande dialogruta: anteckningar! ShowOpenSaveDialog. Det här skriptet utvärderar variabeln pszCaption för att avgöra om den aktuella dialogrutan är en "Öppna"-dialogruta eller om det är en dialogruta för "Spara som". Om det är en öppen dialogruta fortsätter kodkörningen. Om det är en spara som-dialogruta stoppas kodkörningen och felsökningsprogrammet bryter sig in.
// 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");
}
}
Det här kommandot anger en brytpunkt på notepad!ShowOpenSaveDialog och kör skriptet ovan när brytpunkten nås.
bp notepad!ShowOpenSaveDialog ".scriptrun C:\\WinDbg\\Scripts\\DebugHandler.js"
När alternativet Spara fil > väljs i anteckningar körs skriptet, g-kommandot skickas inte och en brytning i kodkörningen sker.
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
Arbeta med 64-bitarsvärden i JavaScript-tillägg
I det här avsnittet beskrivs hur 64-bitarsvärden som skickas till ett JavaScript-felsökningstillägg fungerar. Det här problemet uppstår eftersom JavaScript bara har möjlighet att lagra nummer med hjälp av 53-bitars.
64-bitars och JavaScript 53-bitars lagring
Ordningsvärden som skickas till JavaScript hanteras normalt som JavaScript-nummer. Problemet med detta är att JavaScript-nummer är 64-bitars flyttal med dubbel precision. Alla ordningstal över 53 bitar skulle förlora precision vid inmatning i JavaScript. Det här är ett problem för 64-bitars pekare och andra 64-bitars ordinalvärden som kan ha flaggor i de högsta byten. För att hantera detta kommer alla 64-bitars interna värden (oavsett om de kommer från inbyggd kod eller datamodellen) in i JavaScript som en bibliotekstyp – inte som ett JavaScript-nummer. Den här bibliotekstypen går tillbaka till intern kod utan att förlora numerisk precision.
Automatisk konvertering
Bibliotekstypen för 64-bitars ordnala värden stöder standard JavaScript valueOf-konvertering. Om objektet används i en matematisk åtgärd eller en annan konstruktion som kräver värdekonvertering konverteras det automatiskt till ett JavaScript-nummer. Om precisionsförlust skulle inträffa (värdet använder mer än 53 bitars ordningstalsprecision) utlöser JavaScript-providern ett undantag.
Observera att om du använder bitvis operatorer i JavaScript är du ytterligare begränsad till 32-bitars ordningstalsprecision.
Den här exempelkoden summerar två tal och används för att testa konverteringen av 64-bitarsvärden.
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);
}
Använd en textredigerare som Anteckningar för att skapa en textfil med namnet PlayWith64BitValues.js
Använd kommandot .scriptload för att läsa in skriptet.
0:000> .scriptload c:\WinDbg\Scripts\PlayWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\PlayWith64BitValues.js'
Om du vill göra skriptet lite enklare att arbeta med tilldelar du en variabel i felsökningsprogrammet för att lagra innehållet i skriptet med hjälp av dx-kommandot.
0:000> dx @$myScript = Debugger.State.Scripts.PlayWith64BitValues.Contents
Använd dx-uttrycksutvärderingen för att anropa funktionen addTwoValues.
Först beräknar vi värdet 2^53 =9007199254740992 (Hex 0x20000000000000).
Först ska vi testa (2^53) – 2 och se att det returnerar rätt värde för summan.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740990)
Sum >> 18014398509481980
Sedan beräknar vi (2^53) -1 =9007199254740991. Detta returnerar felet som anger att konverteringsprocessen förlorar precision, så det här är det största värdet som kan användas med sum-metoden i JavaScript-kod.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number
Anropa en datamodellmetod som skickar 64-bitarsvärden. Det finns ingen förlust av precision här.
0:001> dx @$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, (x, y) => x + y)
@$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, (x, y) => x + y) : 0xfffffffffffffffe
Jämförelse
64-bitarsbibliotekstypen är ett JavaScript-objekt och inte en värdetyp, till exempel ett JavaScript-nummer. Detta har vissa konsekvenser för jämförelseåtgärder. Normalt skulle likhet (==) för ett objekt indikera att operander refererar till samma objekt och inte samma värde. JavaScript-providern minimerar detta genom att spåra livereferenser till 64-bitarsvärden och returnera samma "oföränderliga" objekt för icke-insamlade 64-bitarsvärden. Det innebär att följande för jämförelse skulle inträffa.
// 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");
Använd en textredigerare som Anteckningar för att skapa en textfil med namnet ComparisonWith64BitValues.js
Använd kommandot .scriptload för att läsa in skriptet.
0:000> .scriptload c:\WinDbg\Scripts\ComparisonWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\ComparisonWith64BitValues.js'
Om du vill göra skriptet lite enklare att arbeta med tilldelar du en variabel i felsökningsprogrammet för att lagra innehållet i skriptet med hjälp av dx-kommandot.
0:000> dx @$myScript = Debugger.State.Scripts.comparisonWith64BitValues.Contents
Först ska vi testa (2^53) – 2 och se att det returnerar de förväntade värdena.
0:001> dx @$myScript.comparisonWith64BitValues(9007199254740990, 9007199254740990)
areEqual >> true
areNotEqual >> false
isEqualTo42 >> false
isLess >> false
Vi provar också siffran 42 som det första värdet för att verifiera att jämförelseoperatorn fungerar som den ska.
0:001> dx @$myScript.comparisonWith64BitValues(42, 9007199254740990)
areEqual >> false
areNotEqual >> true
isEqualTo42 >> true
isLess >> true
Sedan beräknar vi (2^53) -1 =9007199254740991. Det här värdet returnerar felet som anger att konverteringsprocessen förlorar precision, så det här är det största värdet som kan användas med jämförelseoperatorerna i JavaScript-kod.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number
Upprätthålla precision i åtgärder
För att ett felsökningstillägg ska kunna upprätthålla precisionen projiceras en uppsättning matematiska funktioner ovanpå 64-bitarsbibliotekstypen. Om tillägget behöver (eller eventuellt) behöver precision över 53 bitar för inkommande 64-bitarsvärden bör följande metoder användas i stället för att förlita sig på standardoperatorer:
| Metodnamn | Underskrift | Beskrivning |
|---|---|---|
| asNumber | .asNumber() | Konverterar 64-bitarsvärdet till ett JavaScript-nummer. Om precisionsförlust inträffar utlöses **ETT UNDANTAG** |
| convertToNumber | .convertToNumber() | Konverterar 64-bitarsvärdet till ett JavaScript-nummer. Om precisionsförlust inträffar utlöses **INGET UNDANTAG** |
| getLowPart | .getLowPart() | Konverterar de nedre 32 bitarna av ett 64-bitarsvärde till ett JavaScript-nummer |
| getHighPart | .getHighPart() | Konverterar de mest betydande 32 bitarna av 64-bitarsvärdet till ett JavaScript-nummer |
| lägg till | .add(value) | Lägger till ett värde i 64-bitarsvärdet och returnerar resultatet |
| subtrahera | .subtract(value) | Subtraherar ett värde från 64-bitarsvärdet och returnerar resultatet |
| multiplicera | .multiply(value) | Multiplicerar 64-bitarsvärdet med det angivna värdet och returnerar resultatet |
| divide | .divide(value) | Delar upp 64-bitarsvärdet med det angivna värdet och returnerar resultatet |
| bitwiseAnd | .bitwiseAnd(value) | Beräknar bitvis och av 64-bitarsvärdet med det tillhandahållna värdet och returnerar resultatet |
| bitwiseOr | .bitwiseOr(value) | Beräknar bitvis eller 64-bitarsvärdet med det angivna värdet och returnerar resultatet |
| bitwiseXor | .bitwiseXor(value) | Beräknar bitvis xor för 64-bitarsvärdet med det angivna värdet och returnerar resultatet |
| bitwiseShiftLeft | .bitwiseShiftLeft(value) | Flyttar det 64-bitars värde som lämnas av det angivna beloppet och returnerar resultatet |
| bitwiseShiftRight | .bitwiseShiftRight(värde) | Flyttar 64-bitarsvärdet till höger med det angivna beloppet och returnerar resultatet |
| toString | .toString([radix]) | Konverterar 64-bitarsvärdet till en visningssträng i standardradixet (eller radixet som eventuellt har angetts) |
Den här metoden är också tillgänglig.
| Metodnamn | Underskrift | Beskrivning |
|---|---|---|
| compareTo | .compareTo(value) | Jämför 64-bitarsvärdet med ett annat 64-bitarsvärde. |
JavaScript-felsökning
I det här avsnittet beskrivs hur du använder felsökningsfunktionerna för skript i felsökningsprogrammet. Felsökningsprogrammet har integrerat stöd för felsökning av JavaScript-skript med hjälp av kommandot .scriptdebug (Debug JavaScript).
Anmärkning
Om du vill använda JavaScript-felsökning med WinDbg kör du felsökningsprogrammet som administratör.
Använd den här exempelkoden för att utforska felsökning av ett JavaScript. I den här genomgången ger vi den namnet DebuggableSample.js och sparar den i katalogen 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
//
}
Läs in exempelskriptet.
.scriptload C:\MyScripts\DebuggableSample.js
Börja felsöka skriptet aktivt med hjälp av kommandot .scriptdebug .
0:000> .scriptdebug C:\MyScripts\DebuggableSample.js
>>> ****** DEBUGGER ENTRY DebuggableSample ******
No active debug event!
>>> Debug [DebuggableSample <No Position>] >
När du ser uppmaningen >>> Debug [DebuggableSample <No Position>] > och en begäran om indata finns du i skriptfelsökaren.
Använd kommandot .help för att visa en lista över kommandon i JavaScript-felsökningsmiljön.
>>> 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
Använd kommandot sx för skriptfelsökning för att se listan över händelser som vi kan fånga.
>>> 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
Använd kommandot sxe script debugger för att aktivera break on entry så att skriptet kommer att svälla in i skriptfelsökaren så snart någon kod i det körs.
>>> Debug [DebuggableSample <No Position>] >sxe en
sxe en
Event filter 'en' is now active
Avsluta skriptfelsökaren så gör vi ett funktionsanrop till skriptet som kommer att svälla in i felsökningsprogrammet.
>>> Debug [DebuggableSample <No Position>] >q
Nu är du tillbaka i det normala felsökningsprogrammet. Kör följande kommando för att anropa skriptet.
dx @$scriptContents.outermost()
Nu är du tillbaka i skriptfelsökaren och har brutit dig in på den första raden i den yttersta JavaScript-funktionen.
>>> ****** SCRIPT BREAK DebuggableSample [BreakIn] ******
Location: line = 73, column = 5
Text: var x = 99
>>> Debug [DebuggableSample 73:5] >
Förutom att se inbrytningen i felsökningsprogrammet får du information på raden (73) och kolumnen (5) där pausen ägde rum samt relevant kodfragment av källkod: var x = 99.
Låt oss gå några gånger och komma till en annan plats i skriptet.
p
t
p
t
p
p
Vid denna punkt bör du vara inne i metoden throwAndCatch på rad 34.
...
>>> ****** SCRIPT BREAK DebuggableSample [Step Complete] ******
Location: line = 34, column = 5
Text: var curProc = host.currentProcess
Du kan verifiera detta genom att köra en stackspårning.
>>> 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())
Härifrån kan du undersöka värdet för variabler.
>>> 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
Nu ska vi ange en brytpunkt på den aktuella kodraden och se vilka brytpunkter som nu har angetts.
>>> 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
Härifrån inaktiverar vi "entry (en)"-händelsen med hjälp av sxd-skriptfelsökarens kommando.
>>> Debug [DebuggableSample 34:5] >sxd en
sxd en
Event filter 'en' is now inactive
Och sedan bara gå och låt skriptet fortsätta till slutet.
>>> Debug [DebuggableSample 34:5] >g
g
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
...
Kör skriptmetoden igen och observera när vår brytpunkt träffas.
0:000> dx @$scriptContents.outermost()
inside outer!
>>> ****** SCRIPT BREAK DebuggableSample [Breakpoint 1] ******
Location: line = 34, column = 5
Text: var curProc = host.currentProcess
Visa anropsstacken.
>>> 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())
Nu vill vi sluta felsöka det här skriptet, så vi kopplar från det.
>>> Debug [DebuggableSample 34:5] >.detach
.detach
Debugger has been detached from script!
Och skriv sedan q för att avsluta.
q
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
Om du kör funktionen igen bryts den inte längre in i felsökningsprogrammet.
0:007> dx @$scriptContents.outermost()
inside outer!
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
JavaScript i VS Code – Lägga till IntelliSense
Om du vill arbeta med felsökningsdatamodellobjekten i VS Code kan du använda en definitionsfil som är tillgänglig i Windows-utvecklingspaketen. IntelliSense-definitionsfilen ger stöd för alla host.*-API:er för felsökningsobjektet. Om du har installerat satsen i standardkatalogen på en 64-bitarsdator finns den här:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\JsProvider.d.ts
Så här använder du IntelliSense-definitionsfilen i VS Code:
Leta upp definitionsfilen – JSProvider.d.ts
Kopiera definitionsfilen till samma mapp som skriptet.
Lägg till
/// <reference path="JSProvider.d.ts" />överst i JavaScript-skriptfilen.
Med den referensen i JavaScript-filen ger VS Code dig automatiskt IntelliSense på de värd-API:er som tillhandahålls av JSProvider utöver strukturerna i skriptet. Skriv till exempel "värd". och du ser IntelliSense för alla tillgängliga API:er för felsökningsmodellen.
JavaScript-resurser
Följande är JavaScript-resurser som kan vara användbara när du utvecklar JavaScript-felsökningstillägg.