Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu konuda, hata ayıklayıcı nesnelerini anlayan ve hata ayıklayıcının özelliklerini genişletip özelleştiren betikler oluşturmak için JavaScript'in nasıl kullanılacağı açıklanmaktadır.
JavaScript Hata Ayıklayıcısı Betiğine Genel Bakış
Betik sağlayıcıları, bir betik dilini hata ayıklayıcının iç nesne modeline köprüler. JavaScript hata ayıklayıcı betik sağlayıcısı, JavaScript'i hata ayıklayıcı ile kullanmanıza olanak tanır.
.scriptload komutu aracılığıyla bir JavaScript yüklendiğinde, betiğin kök kodu yürütülür, betikte bulunan adlar hata ayıklayıcının kök ad alanına (dx Debugger) bağlanır ve betik boşaltılana ve nesnelerine yapılan tüm başvurular serbest bırakılana kadar bellekte kalır. Betik, hata ayıklayıcının ifade değerlendiricisine yeni işlevler sağlayabilir, hata ayıklayıcının nesne modelini değiştirebilir veya NatVis görselleştiricisinin yaptığı gibi görselleştirici işlevi görebilir.
Bu konu başlığında JavaScript hata ayıklayıcısı betiğiyle yapabileceklerinden bazıları açıklanmaktadır.
Bu iki konu, hata ayıklayıcıda JavaScript ile çalışma hakkında ek bilgi sağlar.
JavaScript Hata Ayıklayıcısı Örnek Betikleri
JavaScript Uzantılarında Yerel Nesneler
JavaScript Betik Videosu
Defrag Araçları #170 - Andy ve Bill, hata ayıklayıcıda JavaScript genişletilebilirliği ve betik yazma yeteneklerini gösterir.
Hata Ayıklayıcısı JavaScript Sağlayıcısı
Hata ayıklayıcıya dahil edilen JavaScript sağlayıcısı, en son ECMAScript6 nesne ve sınıf geliştirmelerinden tam olarak yararlanır. Daha fazla bilgi için bkz. ECMAScript 6 — Yeni Özellikler: Genel Bakış ve Karşılaştırma.
JsProvider.dll
JsProvider.dll, JavaScript Hata Ayıklayıcı Betiği desteği için yüklenen JavaScript sağlayıcısıdır.
Gereksinimler
JavaScript Hata Ayıklayıcısı Betiği, Windows'un desteklenen tüm sürümleriyle çalışacak şekilde tasarlanmıştır.
JavaScript Betik Sağlayıcısını Yükleme
.script komutlarından herhangi birini kullanmadan önce bir betik sağlayıcısının yüklenmesi gerekir. JavaScript sağlayıcısının yüklendiğini onaylamak için .scriptproviders komutunu kullanın.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
JavaScript Komut Dosyası Meta Komutları
JavaScript Hata Ayıklama Betiği ile çalışmak için aşağıdaki komutlar kullanılabilir.
- .scriptproviders (Betiği Sağlayıcıları Listele)
- .scriptload (Komut Dosyasını Yükle)
- .scriptunload (Betiği Kaldır)
- .scriptrun (Betiği Çalıştır)
- .scriptlist (Yüklenen Betikleri Listele)
Gereksinimler
.script komutlarından herhangi birini kullanmadan önce bir betik sağlayıcısının yüklenmesi gerekir. JavaScript sağlayıcısının yüklendiğini onaylamak için .scriptproviders komutunu kullanın.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
.scriptproviders (Betik Sağlayıcılarını Listele)
.scriptproviders komutu, şu anda hata ayıklayıcısı ve bunların kaydedildiği uzantı tarafından anlaşılan tüm betik dillerini listeler.
Aşağıdaki örnekte JavaScript ve NatVis sağlayıcıları yüklenir.
0:000> .scriptproviders
Available Script Providers:
NatVis (extension '.NatVis')
JavaScript (extension '.js')
".NatVis" uzantısıyla biten herhangi bir dosya bir NatVis betiği olarak, ".js" ile biten herhangi bir dosya ise bir JavaScript betiği olarak anlaşılır. Her iki betik türü de .scriptload komutuyla yüklenebilir.
Daha fazla bilgi için bkz . .scriptproviders (Liste Betiği Sağlayıcıları)
.scriptload (Betiği Yükle)
.scriptload komutu bir betik yükler ve bir betiğin kök kodunu ve initializeScript işlevini yürütür. Betiğin ilk yükünde ve yürütülmesinde herhangi bir hata varsa, hatalar konsolda görüntülenir. Aşağıdaki komut, TestScript.js'nin başarılı yüklemesini gösterir.
0:000> .scriptload C:\WinDbg\Scripts\TestScript.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\TestScript.js'
Betik tarafından yapılan tüm nesne modeli işlemeleri, betik daha sonra kaldırılana veya farklı içerikle yeniden çalıştırılana kadar yerinde kalır.
Daha fazla bilgi için bkz . .scriptload (Load Script)
.scriptrun
.scriptrun komutu bir betik yükler, betiğin kök kodunu, initializeScript ve invokeScript işlevini yürütür. Betiğin ilk yükünde ve yürütülmesinde herhangi bir hata varsa, hatalar konsolda görüntülenir.
0:000> .scriptrun C:\WinDbg\Scripts\helloWorld.js
JavaScript script successfully loaded from 'C:\WinDbg\Scripts\helloWorld.js'
Hello World! We are in JavaScript!
Betik tarafından yapılan tüm hata ayıklayıcısı nesne modeli işlemeleri, betik daha sonra kaldırılana veya farklı içerikle yeniden çalıştırılana kadar yerinde kalır.
Daha fazla bilgi için bkz . .scriptrun (Betiği Çalıştır).
.scriptunload (Betik Yüklemeyi Kaldır)
.scriptunload komutu yüklü bir betiği kaldırır ve uninitializeScript işlevini çağırır. Betiği kaldırmak için aşağıdaki komut söz dizimini kullanın
0:000:x86> .scriptunload C:\WinDbg\Scripts\TestScript.js
JavaScript script unloaded from 'C:\WinDbg\Scripts\TestScript.js'
Daha fazla bilgi için bkz . .scriptunload (Betiği Kaldır).
.scriptlist (Yüklenen Betikleri Listele)
.scriptlist komutu, .scriptload veya .scriptrun komutu aracılığıyla yüklenen tüm betikleri listeler. TestScript .scriptload kullanılarak başarıyla yüklendiyse, .scriptlist komutu yüklenen betiğin adını görüntüler.
0:000> .scriptlist
Command Loaded Scripts:
JavaScript script from 'C:\WinDbg\Scripts\TestScript.js'
Daha fazla bilgi için bkz . .scriptlist (Yüklenen Betikleri Listeleme).
JavaScript Hata Ayıklayıcısı Betiğini Kullanmaya Başlama
HelloWorld Örnek Betiği
Bu bölümde, Hello World adlı çıktısını alan basit bir JavaScript hata ayıklayıcısı betiğinin nasıl oluşturulacağı ve yürütülacağı açıklanmaktadır.
// WinDbg JavaScript sample
// Prints Hello World
function initializeScript()
{
host.diagnostics.debugLog("***> Hello World! \n");
}
Yukarıda gösterilen JavaScript kodunu içeren HelloWorld.js adlı bir metin dosyası oluşturmak için Not Defteri gibi bir metin düzenleyicisi kullanın.
Betiği yüklemek ve yürütmek için .scriptload komutunu kullanın. initializeScript işlev adını kullandığımızdan, betik yüklendiğinde işlevdeki kod çalıştırılır.
0:000> .scriptload c:\WinDbg\Scripts\HelloWorld.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\HelloWorld.js'
***> Hello World!
Betik yüklendikten sonra hata ayıklayıcıda ek işlevler kullanılabilir. Betiğimizin artık yerleşik olduğunu görmek için Debugger.State.Scripts dosyasını görüntülemek için dx (NatVis İfadesini Görüntüle) komutunu kullanın.
0:000> dx Debugger.State.Scripts
Debugger.State.Scripts
HelloWorld
Sonraki örnekte adlandırılmış bir işlev ekleyip çağıracağız.
İki Değer Ekleme Örnek Betiği
Bu bölümde, giriş alan ve iki sayı ekleyen basit bir JavaScript hata ayıklayıcısı betiğinin nasıl oluşturulacağı ve yürütülacağı açıklanmaktadır.
Bu basit betik, addTwoValues adlı tek bir işlev sağlar.
// WinDbg JavaScript sample
// Adds two functions
function addTwoValues(a, b)
{
return a + b;
}
FirstSampleFunction.js adlı bir metin dosyası oluşturmak için Not Defteri gibi bir metin düzenleyicisi kullanın
Betiği yüklemek için .scriptload komutunu kullanın.
0:000> .scriptload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'
Betik yüklendikten sonra hata ayıklayıcıda ek işlevler kullanılabilir. Betiğimizin artık yerleşik olduğunu görmek için dx (NatVis İfadesini Görüntüle) komutunu kullanarak Debugger.State.Scripts'i görüntüleyin.
0:000> dx Debugger.State.Scripts
Debugger.State.Scripts
FirstSampleFunction
Hangi işlevleri sağladığını görmek için FirstSampleFunction'ı seçebiliriz.
0:000> dx -r1 -v Debugger.State.Scripts.FirstSampleFunction.Contents
Debugger.State.Scripts.FirstSampleFunction.Contents : [object Object]
host : [object Object]
addTwoValues
...
Betiğin biraz daha kullanışlı bir şekilde çalışması için hata ayıklayıcıda dx komutunu kullanarak betiğin içeriğini tutacak bir değişken atayın.
0:000> dx @$myScript = Debugger.State.Scripts.FirstSampleFunction.Contents
addTwoValues işlevini çağırmak için dx ifade değerlendiricisini kullanın.
0:000> dx @$myScript.addTwoValues(10, 41),d
@$myScript.addTwoValues(10, 41),d : 51
Betiklerle çalışmak için @$scriptContents yerleşik takma adını da kullanabilirsiniz. @$scriptContents diğer adı, yüklenen tüm betiklerin .Content ögelerini birleştirir.
0:001> dx @$scriptContents.addTwoValues(10, 40),d
@$scriptContents.addTwoValues(10, 40),d : 50
Betikle çalışmayı bitirdiğinizde betiği kaldırmak için .scriptunload komutunu kullanın.
0:000> .scriptunload c:\WinDbg\Scripts\FirstSampleFunction.js
JavaScript script successfully unloaded from 'c:\WinDbg\Scripts\FirstSampleFunction.js'
Hata Ayıklayıcı Komut Otomasyonu
Bu bölümde u (Unassemble) komutunun gönderilmesini otomatik hale getiren basit bir JavaScript hata ayıklayıcısı betiğinin nasıl oluşturulacağı ve yürütüldiği açıklanır. Örnek ayrıca bir döngüde komut çıktısının nasıl toplanıp görüntüleneceğini de gösterir.
Bu betik, RunCommands() adlı tek bir işlev sağlar.
// 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");
}
RunCommands.js adlı bir metin dosyası oluşturmak için Not Defteri gibi bir metin düzenleyicisi kullanın
RunCommands betiğini yüklemek için .scriptload komutunu kullanın.
0:000> .scriptload c:\WinDbg\Scripts\RunCommands.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\RunCommands.js'
Betik yüklendikten sonra hata ayıklayıcıda ek işlevler kullanılabilir. Komut dosyamızın artık yerleşik olduğunu görmek için dx (NatVis İfadesini Görüntüle) komutunu kullanarak Debugger.State.Scripts.RunCommands ifadesini görüntüleyin.
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]
RunCommands betiğinde RunCommands işlevini çağırmak için dx komutunu kullanın.
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
Özel JavaScript Hata Ayıklayıcısı İşlevleri
Bir JavaScript betiğinde betik sağlayıcısının kendisi tarafından çağrılan birkaç özel işlev vardır.
initializeScript
JavaScript betiği yüklenip yürütülürken, betikteki değişkenler, işlevler ve diğer nesneler hata ayıklayıcının nesne modelini etkilemeden önce bir dizi adımdan geçer.
- Betik belleğe yüklenir ve ayrıştırılır.
- Betikteki ana kod yürütülür.
- Betik initializeScript adlı bir yönteme sahipse, bu yöntem çağrılır.
- initializeScript'ten dönüş değeri, hata ayıklayıcının nesne modelinin otomatik olarak nasıl değiştirileceğini belirlemek için kullanılır.
- Betikteki adlar, hata ayıklayıcının ad alanına bağlanır.
Belirtildiği gibi, betiğin kök kodu yürütüldükten hemen sonra initializeScript çağrılır. Görevi, hata ayıklayıcının nesne modelinin nasıl değiştirildiğini gösteren bir JavaScript kayıt nesneleri dizisinin sağlayıcıya döndürülmesidir.
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
invokeScript yöntemi birincil betik yöntemidir ve .scriptload ve .scriptrun çalıştırıldığında çağrılır.
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
uninitializeScript yöntemi initializeScript'in davranışsal tersidir. Bir betiğin bağlantısı kaldırıldığında ve kaldırılmaya hazır olduğunda çağrılır. Görevi, betiğin yürütme sırasında kesin olarak yaptığı nesne modelinde yapılan değişiklikleri geri almak ve/veya betiğin önbelleğe aldığı nesneleri yok etmektir.
Bir betik nesne modeline kesinlik temelli işlemeler yapmaz veya sonuçları önbelleğe almazsa, uninitializeScript yöntemine sahip olması gerekmez. initializeScript'in dönüş değeri tarafından belirtilen şekilde gerçekleştirilen nesne modelinde yapılan tüm değişiklikler sağlayıcı tarafından otomatik olarak geri alınır. Bu tür değişiklikler için açık bir uninitializeScript yöntemi gerekmez.
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");
}
Betik Komutları Tarafından Çağrılan İşlevlerin Özeti
Bu tabloda betik komutları tarafından hangi işlevlerin çağrıldığı özetlenmektedir
| Komut | .scriptload | .scriptrun (Betiği Çalıştır) | .scriptunload (Betiği Kaldır) |
|---|---|---|---|
| kök | evet | evet | |
| initializeScript | evet | evet | |
| invokeScript | evet | ||
| uninitializeScript | evet |
Betik yüklenirken, yürütülürken ve kaldırılırken her işlevin ne zaman çağrıldığını görmek için bu örnek kodu kullanı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");
}
JavaScript'te Hata Ayıklayıcı Görselleştiricisi Oluşturma
Özel görselleştirme dosyaları, verileri veri ilişkilerini ve içeriği daha iyi yansıtan bir görselleştirme yapısında gruplandırmanıza ve düzenlemenize olanak sağlar. JavaScript hata ayıklayıcısı uzantılarını kullanarak NatVis'e çok benzer şekilde davranan hata ayıklayıcısı görselleştiricileri yazabilirsiniz. Bu, belirli bir veri türü için görselleştirici işlevi gören bir JavaScript prototip nesnesi (veya ES6 sınıfı) yazma yoluyla gerçekleştirilir. NatVis ve hata ayıklayıcı hakkında daha fazla bilgi için bkz. dx (NatVis İfadesini Görüntüle).
Örnek sınıf - Simple1DArray
Tek boyutlu bir diziyi temsil eden bir C++ sınıfı örneğini düşünün. Bu sınıfın, dizinin genel boyutu olan m_size ve bellekteki m_size alanına eşit sayıda inte işaretçisi olan m_pValues olmak üzere iki üyesi vardır.
class Simple1DArray
{
private:
ULONG64 m_size;
int *m_pValues;
};
Varsayılan veri yapısı işlemesine bakmak için dx komutunu kullanabiliriz.
0:000> dx g_array1D
g_array1D [Type: Simple1DArray]
[+0x000] m_size : 0x5 [Type: unsigned __int64]
[+0x008] m_pValues : 0x8be32449e0 : 0 [Type: int *]
JavaScript Görselleştiricisi
Bu türü görselleştirmek için, hata ayıklayıcının göstermesini istediğimiz tüm alanlara ve özelliklere sahip bir prototip (veya ES6) sınıfı yazmamız gerekir. Ayrıca initializeScript yönteminin, JavaScript sağlayıcısına prototipimizi verilen tür için görselleştirici olarak bağlamasını söyleyen bir nesne döndürmesini de sağlamalıyız.
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")];
}
Betiği arrayVisualizer.jsadlı bir dosyaya kaydedin.
JavaScript sağlayıcısını yüklemek için .load (Uzantı DLL'sini Yükle) komutunu kullanın.
0:000> .load C:\ScriptProviders\jsprovider.dll
Dizi görselleştirici betiğini yüklemek için .scriptload kullanın.
0:000> .scriptload c:\WinDbg\Scripts\arrayVisualizer.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\arrayVisualizer.js'
Şimdi, dx komutu kullanıldığında betik görselleştiricisi dizi içeriğinin satırlarını görüntüler.
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
Buna ek olarak, bu JavaScript görselleştirmesi Select gibi LINQ işlevleri sağlar.
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
Görselleştirmeyi Etkileyenler
initializeScript'ten host.typeSignatureRegistration nesnesinin döndürülmesi yoluyla yerel bir tür için görselleştirici olarak yapılandırılmış bir prototip veya sınıf, JavaScript içindeki tüm özellikleri ve yöntemleri yerel türe ekler. Ayrıca aşağıdaki semantikler de geçerlidir:
İki alt çizgi (__) ile başlamayan tüm adlar görselleştirmede kullanılabilir.
Standart JavaScript nesnelerinin parçası olan veya JavaScript sağlayıcısının oluşturduğu protokollerin bir parçası olan adlar görselleştirmede gösterilmez.
[Symbol.iterator] desteğiyle bir nesne yinelenebilir hale getirilebilir.
Bir nesne, çeşitli işlevlerden oluşan özel bir protokolün desteğiyle dizine alınabilir: getDimensionality, getValueAt ve isteğe bağlı olarak setValueAt.
Yerel ve JavaScript Nesne Köprüsü
JavaScript ile hata ayıklayıcının nesne modeli arasındaki köprü iki yönlüdür. Yerel nesneler JavaScript'e geçirilebilir ve JavaScript nesneleri Hata Ayıklayıcı'nın ifade değerlendiricisine geçirilebilir. Bunun bir örneği olarak, betiğimize aşağıdaki yöntemin eklenmesini göz önünde bulundurun:
function multiplyBySeven(val)
{
return val * 7;
}
Bu yöntem artık yukarıdaki örnek LINQ sorgusunda kullanılabilir. İlk olarak JavaScript görselleştirmesini yükleyeceğiz.
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
Ardından aşağıda gösterildiği gibi satır içi multiplyBySeven işlevini kullanabiliriz.
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
JavaScript ile Koşullu Kesme Noktaları
Bir kesme noktasına çarptıktan sonra ek işlem yapmak için JavaScript'i kullanabilirsiniz. Örneğin, betik, diğer çalışma zamanı değerlerini inceleyerek, kod yürütmesini otomatik olarak devam ettirip ettirmeyeceğinizi veya durdurup el ile daha fazla hata ayıklama yapmanız gerekip gerekmediğini belirlemek için kullanılabilir.
Kesme noktalarıyla çalışma hakkında genel bilgi için bkz. Kesme Noktalarını Denetleme Yöntemleri.
DebugHandler.js Örnek Kesme Noktası İşleme Betiği
Bu örnek, not defterinin aç ve kaydet iletişim kutusunu değerlendirir: not defteri! ShowOpenSaveDialog. Bu betik, geçerli iletişim kutusunun "Aç" iletişim kutusu mu yoksa "Farklı Kaydet" iletişim kutusu mu olduğunu belirlemek için pszCaption değişkenini değerlendirir. Açık bir iletişim kutusuysa kod yürütme devam eder. Bu bir farklı kaydet iletişim kutusuysa, kod yürütme duracak ve hata ayıklayıcı devreye girecektir.
// 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");
}
}
Bu komut, notepad!ShowOpenSaveDialog üzerinde bir kesme noktası ayarlar ve bu kesme noktasına her gelindiğinde yukarıdaki betiği çalıştırır.
bp notepad!ShowOpenSaveDialog ".scriptrun C:\\WinDbg\\Scripts\\DebugHandler.js"
Ardından not defterinde Dosya > Kaydet seçeneği belirlendiğinde betik çalıştırılır, g komutu gönderilmez ve kod yürütmede bir kesme gerçekleşir.
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
JavaScript Uzantılarında 64 Bit Değerlerle Çalışma
Bu bölümde, JavaScript hata ayıklayıcısı uzantısına geçirilen 64 bit değerlerin nasıl davrandığı açıklanmaktadır. JavaScript yalnızca 53 bit kullanarak sayıları depolama özelliğine sahip olduğundan bu sorun ortaya çıkar.
64 Bit ve JavaScript 53 Bit Depolama
JavaScript'e geçirilen sıralı değerler normalde JavaScript numaraları olarak sıralanır. Buradaki sorun JavaScript numaralarının 64 bit çift duyarlıklı kayan nokta değerleri olmasıdır. 53 bit'in üzerindeki herhangi bir sıralı sayı, JavaScript'e girişte kesinlik kaybeder. Bu, en yüksek baytta bayraklara sahip olabilecek 64 bit işaretçiler ve diğer 64 bit sıralı değerler için bir sorun sunar. Bununla başa çıkmak için, JavaScript'e aktarılan herhangi bir 64 bit yerel değer (ister yerel koddan ister veri modelinden gelsin) JavaScript sayısı olarak değil, bir kütüphane tipi olarak girer. Bu kitaplık türü, sayısal duyarlığı kaybetmeden yerel koda gidiş-dönüş sağlar.
Otomatik Dönüştürme
64 bit sıralı değerler için kitaplık türü, standart JavaScript valueOf dönüştürmesini destekler. Nesne, değer dönüştürme gerektiren bir matematik işleminde veya başka bir yapıda kullanılıyorsa, otomatik olarak bir JavaScript numarasına dönüştürülür. Duyarlık kaybı yaşanırsa (değer 53 bitten fazla sıra duyarlılığı kullanır), JavaScript sağlayıcısı bir özel durum oluşturur.
JavaScript'te bit düzeyinde işleçler kullanıyorsanız 32 bit sıra duyarlılığıyla da sınırlı olduğunuzu unutmayın.
Bu örnek kod iki sayıyı toplar ve 64 bit değerlerin dönüştürülmesi için kullanılır.
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);
}
PlayWith64BitValues.js adlı bir metin dosyası oluşturmak için Not Defteri gibi bir metin düzenleyicisi kullanın
Betiği yüklemek için .scriptload komutunu kullanın.
0:000> .scriptload c:\WinDbg\Scripts\PlayWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\PlayWith64BitValues.js'
Betiğin biraz daha kullanışlı bir şekilde çalışması için hata ayıklayıcıda dx komutunu kullanarak betiğin içeriğini tutacak bir değişken atayın.
0:000> dx @$myScript = Debugger.State.Scripts.PlayWith64BitValues.Contents
addTwoValues işlevini çağırmak için dx ifade değerlendiricisini kullanın.
İlk olarak 2^53 =9007199254740992 (Onaltılık 0x20000000000000) değerini hesaplayacağız.
Test etmek için önce (2^53) - 2 kullanacağız ve toplam için doğru değeri döndürdüğünü göreceğiz.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740990)
Sum >> 18014398509481980
Ardından =9007199254740991 -1 (2^53) hesaplayacağız. Bu, dönüştürme işleminin duyarlığı kaybedeceğini belirten hatayı döndürür, bu nedenle Bu, JavaScript kodunda sum yöntemiyle kullanılabilecek en büyük değerdir.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number
64 bit değerleri geçiren bir veri modeli yöntemi çağır. Burada hassasiyet kaybı yoktur.
0:001> dx @$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, (x, y) => x + y)
@$myScript.performOp64BitValues( 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, (x, y) => x + y) : 0xfffffffffffffffe
Karşılaştırma
64 bit kitaplık türü bir JavaScript nesnesidir ve JavaScript numarası gibi bir değer türü değildir. Bunun karşılaştırma işlemleri için bazı etkileri vardır. Normalde, bir nesnede eşitlik operatörü (==), işlenenlerin aynı nesneye değil aynı değere başvurduğunu belirtir. JavaScript sağlayıcısı, 64 bit değerlere canlı başvuruları izleyerek ve toplanmayan 64 bit değer için aynı "sabit" nesneyi döndürerek bunu azaltır. Bu, karşılaştırma için aşağıdakilerin gerçekleşeceği anlamına gelir.
// 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");
ComparisonWith64BitValues.js adlı bir metin dosyası oluşturmak için Not Defteri gibi bir metin düzenleyicisi kullanın
Betiği yüklemek için .scriptload komutunu kullanın.
0:000> .scriptload c:\WinDbg\Scripts\ComparisonWith64BitValues.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\ComparisonWith64BitValues.js'
Betiğin biraz daha kullanışlı bir şekilde çalışması için hata ayıklayıcıda dx komutunu kullanarak betiğin içeriğini tutacak bir değişken atayın.
0:000> dx @$myScript = Debugger.State.Scripts.comparisonWith64BitValues.Contents
Test etmek için önce (2^53) - 2 kullanacağız ve beklenen değerleri döndürdüğünü göreceğiz.
0:001> dx @$myScript.comparisonWith64BitValues(9007199254740990, 9007199254740990)
areEqual >> true
areNotEqual >> false
isEqualTo42 >> false
isLess >> false
Karşılaştırma işlecinin gerektiği gibi çalıştığını doğrulamak için ilk değer olarak 42 sayısını da deneyeceğiz.
0:001> dx @$myScript.comparisonWith64BitValues(42, 9007199254740990)
areEqual >> false
areNotEqual >> true
isEqualTo42 >> true
isLess >> true
Ardından =9007199254740991 -1 (2^53) hesaplayacağız. Bu değer, dönüştürme işleminin duyarlığı kaybedeceğini belirten hatayı döndürür, bu nedenle Bu, JavaScript kodundaki karşılaştırma işleçleriyle kullanılabilecek en büyük değerdir.
0:000> dx @$myScript.playWith64BitValues(9007199254740990, 9007199254740991)
Error: 64 bit value loses precision on conversion to number
İşlemlerde Duyarlığı Koruma
Bir hata ayıklayıcı uzantısının hassasiyeti korumasına izin vermek için, 64-bit kütüphane türünün üzerine bir dizi matematiksel fonksiyon yansıtılır. Uzantının gelen 64 bit değerler için 53 bit'in üzerinde duyarlığı gerekiyorsa (veya büyük olasılıkla) standart işleçlere güvenmek yerine aşağıdaki yöntemler kullanılmalıdır:
| Yöntem Adı | İmza | Açıklama |
|---|---|---|
| asNumber | .asNumber() | 64 bit değerini JavaScript numarasına dönüştürür. Hassasiyet kaybı oluşursa bir istisna fırlatılır. |
| SayıyaDönüştür | .convertToNumber() | 64 bit değerini JavaScript numarasına dönüştürür. Duyarlık kaybı oluşursa, **HİÇBİR İSTİSNA OLUŞTURULMAZ**. |
| getLowPart | .getLowPart() | 64 bit değerinin daha düşük 32 bit değerini JavaScript numarasına dönüştürür |
| yüksekBölümüAl | .getHighPart() | 64 bit değerinin yüksek 32 bit değerini JavaScript numarasına dönüştürür |
| ekle | .add(değer) | 64 bit değere bir değer ekler ve sonucu döndürür |
| çıkarmak | .subtract(değer) | Bir değeri 64 bit değerinden çıkarır ve sonucu verir |
| çarpma işlemi yapmak | .çarpma(değer) | 64 bit değeri sağlanan değerle çarpar ve sonucu verir |
| bölmek | .divide(değer) | 64 bit değeri sağlanan değere böler ve sonucu döndürür |
| bit düzeyinde ve | .bitwiseAnd(değer) | Sağlanan değerle bit düzeyinde ve 64 bit değerini hesaplar ve sonucu döndürür |
| bit düzeyinde VEYA | .bitwiseOr(değer) | Sağlanan değerle bit düzeyinde veya 64 bit değerini hesaplar ve sonucu döndürür |
| bit düzeyinde XOR | .bitwiseXor(değer) | 64 bit değerin sağlanan değerle bit düzeyinde xor'unu hesaplar ve sonucu döndürür. |
| bitwiseShiftLeft | .bitwiseShiftLeft(değer) | Belirli 64 bit değerini verilen miktar kadar sola kaydırır ve sonucu döndürür. |
| bit düzeyinde sağa kaydırma | .bitwiseShiftRight([değer]) | 64 bit değeri verilen miktara göre sağa kaydırarak sonucu verir |
| toString | .toString([radix]) | 64 bit değerini varsayılan radix'teki (veya isteğe bağlı olarak sağlanan radix) bir görüntüleme dizesine dönüştürür |
Bu yöntem de kullanılabilir.
| Yöntem Adı | İmza | Açıklama |
|---|---|---|
| compareTo | .compareTo(değer) | 64 bit değerini başka bir 64 bit değerle karşılaştırır. |
JavaScript Hata Ayıklama
Bu bölümde, hata ayıklayıcının betik hata ayıklama özelliklerinin nasıl kullanılacağı açıklanmaktadır. Hata ayıklayıcı, .scriptdebug (JavaScript Hatalarını Ayıkla) komutunu kullanarak JavaScript betiklerinin hatalarını ayıklamaya yönelik tümleşik desteğe sahiptir.
Uyarı
WinDbg ile JavaScript Hata Ayıklama'yı kullanmak için hata ayıklayıcısını Yönetici olarak çalıştırın.
JavaScript hatalarını ayıklamayı keşfetmek için bu örnek kodu kullanın. Bu örnek çalışma için ismini DebuggableSample.js koyacağız ve C:\MyScripts dizinine kaydedeceğiz.
"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
//
}
Örnek betiği yükleyin.
.scriptload C:\MyScripts\DebuggableSample.js
.scriptdebug komutunu kullanarak betikte etkin bir şekilde hata ayıklamaya başlayın.
0:000> .scriptdebug C:\MyScripts\DebuggableSample.js
>>> ****** DEBUGGER ENTRY DebuggableSample ******
No active debug event!
>>> Debug [DebuggableSample <No Position>] >
İstemi >>> Debug [DebuggableSample <No Position>] > ve giriş isteğini gördüğünüzde, betik hata ayıklayıcısına girmişsinizdir.
JavaScript Hata Ayıklama ortamında komutların listesini görüntülemek için .help komutunu kullanı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
Yakalanabilecek olayların listesini görmek için sx betik hata ayıklayıcısı komutunu kullanın.
>>> 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
Sxe betik hata ayıklayıcı komutunu kullanarak girdiyi kesmeyi açın, böylece betikteki herhangi bir kod çalışır çalışmaz hata ayıklayıcıya yakalanacaktır.
>>> Debug [DebuggableSample <No Position>] >sxe en
sxe en
Event filter 'en' is now active
Betik hata ayıklayıcıdan çıkın ve ardından, hata ayıklayıcıya düşecek olan betikte bir işlev çağrısı yapacağız.
>>> Debug [DebuggableSample <No Position>] >q
Bu noktada, normal hata ayıklayıcıya geri dönersiniz. Betiği çağırmak için aşağıdaki komutu yürütün.
dx @$scriptContents.outermost()
Şimdi betik hata ayıklayıcısına geri döndün ve en dıştaki JavaScript işlevinin ilk satırında çalışmayı durdurdun.
>>> ****** SCRIPT BREAK DebuggableSample [BreakIn] ******
Location: line = 73, column = 5
Text: var x = 99
>>> Debug [DebuggableSample 73:5] >
Hata ayıklayıcıda kesmeyi görmenin yanı sıra, kesmenin gerçekleştiği satır (73) ve sütun (5) ve kaynak kodun ilgili kod parçacığı hakkında bilgi alırsınız: var x = 99.
Birkaç kez adım atalım ve betikte başka bir yere gidelim.
p
t
p
t
p
p
Bu noktada, 34. satırdaki throwAndCatch yöntemine bölünmelisiniz.
...
>>> ****** SCRIPT BREAK DebuggableSample [Step Complete] ******
Location: line = 34, column = 5
Text: var curProc = host.currentProcess
Bir yığın izlemesi yürüterek bunu doğrulayabilirsiniz.
>>> 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())
Buradan değişkenlerin değerini araştırabilirsiniz.
>>> 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
Şimdi geçerli kod satırında bir kesme noktası ayarlayalım ve şimdi hangi kesme noktalarının ayarlandığını görelim.
>>> 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
Buradan, sxd betik hata ayıklayıcısı komutunu kullanarak girdi (en) olayını devre dışı bırakacağız.
>>> Debug [DebuggableSample 34:5] >sxd en
sxd en
Event filter 'en' is now inactive
Sonra da betiğin tamamlanmasına kadar devam etmesine izin verin.
>>> Debug [DebuggableSample 34:5] >g
g
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
...
Betik yöntemini tekrar çalıştırarak kesme noktasına ulaşıldığını gözlemleyin.
0:000> dx @$scriptContents.outermost()
inside outer!
>>> ****** SCRIPT BREAK DebuggableSample [Breakpoint 1] ******
Location: line = 34, column = 5
Text: var curProc = host.currentProcess
Çağrı yığınını görüntüleyin.
>>> 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())
Bu noktada, bu betiğin hata ayıklamasını durdurmak istiyoruz, bu yüzden bağlantıyı kesiyoruz.
>>> Debug [DebuggableSample 34:5] >.detach
.detach
Debugger has been detached from script!
Ardından çıkmak için q yazın.
q
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
İşlevin tekrar yürütülmesi artık hata ayıklayıcıya geçmeyecek.
0:007> dx @$scriptContents.outermost()
inside outer!
This is a fun test
Of the script debugger
foo.a = 99
Caught and returned!
Test
VS Code'da JavaScript - IntelliSense ekleme
VS Code'da hata ayıklayıcısı veri modeli nesneleriyle çalışmak isterseniz, Windows geliştirme setlerinde bulunan bir tanım dosyasını kullanabilirsiniz. IntelliSense tanım dosyası tüm konak.* hata ayıklayıcısı nesne API'leri için destek sağlar. Seti varsayılan dizinde 64 bit bilgisayara yüklediyseniz, burada bulunur:
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\winext\JsProvider.d.ts
VS Code'da IntelliSense tanım dosyasını kullanmak için:
Tanım dosyasını bulma - JSProvider.d.ts
Tanım dosyasını betiğinizle aynı klasöre kopyalayın.
JavaScript betik dosyanızın en üstüne ekleyin
/// <reference path="JSProvider.d.ts" />.
JavaScript dosyanızda bu başvuruyla, VS Code, komut dosyanızdaki yapılara ek olarak JSProvider tarafından sağlanan konak API'ler için size otomatik olarak IntelliSense sağlar. Örneğin, "konak" yazın. ve tüm kullanılabilir hata ayıklayıcı modeli API'leri için IntelliSense'i görürsünüz.
JavaScript Kaynakları
JavaScript hata ayıklama uzantıları geliştirirken yararlı olabilecek JavaScript kaynakları aşağıdadır.