Aracılığıyla paylaş


JavaScript Uzantılarında Yerel Hata Ayıklayıcı Nesneleri

Yerel hata ayıklayıcı nesneleri, hata ayıklayıcı ortamının çeşitli yapılarını ve davranışlarını temsil eder. Nesneler, hata ayıklayıcının durumunu değiştirmek için JavaScript uzantılarına geçirilebilir (veya içinde edinilebilir).

Örnek hata ayıklayıcı nesneleri aşağıdakileri içerir.

  • Oturum
  • İş Parçacıkları / İş Parçacığı
  • İşlemler / İşlemler
  • Yığın Çerçeveleri / Yığın Çerçevesi
  • Yerel Değişkenler
  • Modüller / Modül
  • Fayda
  • Devlet
  • Ayarlar

Örneğin host.namespace.Debugger.Utility.Control.ExecuteCommand nesnesi, aşağıdaki iki JavaScript kodu satırıyla u komutunu hata ayıklayıcıya göndermek için kullanılabilir.

var ctl = host.namespace.Debugger.Utility.Control;   
var outputLines = ctl.ExecuteCommand("u");

Bu konuda, ortak nesnelerle nasıl çalışıldığı açıklanır ve öznitelikleri ve davranışları hakkında başvuru bilgileri sağlanır.

JavaScript ile çalışma hakkında genel bilgi için bkz. JavaScript Hata Ayıklayıcısı Betiği Oluşturma. Hata ayıklayıcı nesnelerini kullanan JavaScript örnekleri için bkz. JavaScript Hata Ayıklayıcısı Örnek Betikleri. Ayarlar nesneleriyle çalışma hakkında bilgi için bkz. .settings (Hata Ayıklama Ayarlarını Ayarla).

Hata ayıklayıcı oturumunda kullanılabilen nesneleri keşfetmek için dx (NatVis İfadesini Görüntüle) komutunu kullanın. Örneğin, bu dx komutuyla en üst düzey hata ayıklayıcı nesnelerinden bazılarını görüntüleyebilirsiniz.

0: kd> dx -r2 Debugger
Debugger                
    Sessions         : [object Object]
        [0x0]            : Remote KD: KdSrv:Server=@{<Local>},Trans=@{NET:Port=50000,Key=1.2.3.4,Target}
    Settings        
        Debug           
        Display         
        EngineInitialization
        Extensions      
        Input           
        Sources         
        Symbols         
        AutoSaveSettings : false
    State           
        DebuggerVariables
        PseudoRegisters 
        Scripts         
        UserVariables   
    Utility         
        Collections     
        Control         
        Objects   

Yukarıda listelenen tüm öğeler tıklanabilir DML'dir ve hata ayıklayıcı nesne yapısını görüntülemek için daha aşağı doğru yinelenebilir.

Veri Modeli aracılığıyla Hata Ayıklayıcıyı Genişletme

Hata ayıklayıcısı veri modeli, Windows'ta aşağıdaki özniteliklere sahip uygulamalar ve sürücüler hakkında bilgi almak için bir arabirim oluşturulmasına olanak tanır.

  • Bulunabilir ve düzenlidir; mantıksal olarak yapılandırılmış bir ad alanı dx komutu kullanılarak sorgulanabilir.
  • LINQ kullanılarak sorgulanabilir- Bu, standart sorgu dili kullanılarak verilerin ayıklanıp sıralanmasına olanak tanır.
  • Mantıksal ve tutarlı olarak genişletilebilir - Natvis ve JavaScript gibi hata ayıklayıcı betik sağlayıcılarıyla bu konuda açıklanan teknikler kullanılarak genişletilebilir.

JavaScript'te Hata Ayıklayıcı Nesnesini Genişletme

Betik uzantıları, JavaScript'te görselleştirici oluşturmanın yanı sıra oturumlar, işlemler, iş parçacıkları, yığınlar, yığın çerçeveleri, yerel değişkenler gibi hata ayıklayıcının temel kavramlarını değiştirebilir ve hatta kendilerini diğer uzantıların kullanabileceği uzantı noktaları olarak yayımlayabilir.

Bu bölümde, hata ayıklayıcısı içinde temel kavramın nasıl genişletıldığı açıklanmaktadır. Paylaşılacak şekilde oluşturulan uzantılar , JavaScript Uzantılarında Yerel Hata Ayıklayıcı Nesneleri - Tasarım ve Test Konuları'nda sunulan yönergelere uygun olmalıdır.

Uzantı Kaydetme

Betik, initializeScript yönteminden döndürülen dizideki bir girdi aracılığıyla bir uzantı sağladığı gerçeğini kaydedebilir.

function initializeScript()
{
    return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process")];
}

Döndürülen dizide host.namedModelParent nesnesinin varlığı, hata ayıklayıcıya belirli bir prototip nesnesinin veya ES6 sınıfının (bu örnekte comProcessExtension) Debugger.Models.Process adı altında kayıtlı olan modele bir üst veri modeli olacağını gösterir.

Debugger Nesne Uzantısı Noktaları

Aşağıdaki hata ayıklayıcı uzantı noktaları hata ayıklayıcının ayrılmaz parçasıdır ve JavaScript gibi betik sağlayıcıları tarafından kullanılabilir.

Debugger.Models.Sessions: Hata ayıklayıcının eklendiği oturumların (hedefler) listesi

Debugger.Models.Session: Hata ayıklayıcının bağlı olduğu tek bir oturum (hedef) (canlı kullanıcı modu, KD vb.)

Debugger.Models.Processes: Oturum içindeki işlemlerin listesi

Debugger.Models.Threads: İşlem içindeki iş parçacıklarının listesi

Debugger.Models.Thread: İşlem içindeki tek bir iş parçacığı (kullanıcı veya çekirdek modundan bağımsız olarak)

Debugger.Models.Stack: İş parçacığı yığını

Debugger.Models.StackFrames: Yığın oluşturan çerçeve koleksiyonu

Debugger.Models.StackFrame: Yığın içinde tek bir yığın çerçevesi

Debugger.Models.LocalVariables: Yığın çerçevesi içindeki yerel değişkenler

Debugger.Models.Parameters: Yığın çerçevesindeki bir çağrının parametreleri

Debugger.Models.Module: İşlemin adres alanı içindeki tek bir modül

Ek Veri Modeli Nesneleri

Ayrıca, çekirdek veri modeli tarafından tanımlanan bazı ek veri modeli nesneleri vardır.

DataModel.Models.Intrinsic: İçsel değer (ordinal değerler, float değerler vb.)

DataModel.Models.String: Bir dize

DataModel.Models.Array: Yerel bir dizi

DataModel.Models.Guid: GUID

DataModel.Models.Error: Bir hata nesnesi

DataModel.Models.Concepts.Iterable: Yinelenebilir olan her nesneye uygulanır

DataModel.Models.Concepts.StringDisplayable: Görüntüleme dizesi dönüştürmesi olan her nesneye uygulanır

Örnek COM Hata Ayıklayıcısı Nesne Uzantısına Genel Bakış

Bir örnek düşünelim. Genel arabirim tablosu (GIT) gibi COM'a özgü bilgileri görüntülemek için bir hata ayıklayıcısı uzantısı oluşturmak istediğinizi düşünün.

Geçmişte, COM ile ilgili şeylere erişmek için bir araç sağlayan bir dizi komut içeren mevcut bir hata ayıklayıcı uzantısı olabilir. Bir komut işlem merkezli bilgileri (örneğin genel arabirim tablosu) görüntüleyebilir. Başka bir komut, hangi daire kodunun içinde yürütülmekte olduğu gibi iş parçacığı merkezli bilgiler sağlayabilir. COM'un diğer yönlerini keşfetmek için ikinci bir hata ayıklayıcısı uzantısını bilmeniz ve yüklemeniz gerekebilir.

JavaScript uzantısı, bulunması zor bir komut kümesine sahip olmak yerine hata ayıklayıcının işlem ve iş parçacığı kavramını değiştirerek bu bilgileri doğal, keşfedilebilir ve diğer hata ayıklayıcı uzantılarıyla birleştirilebilir bir şekilde ekleyebilir.

Kullanıcı veya Çekirdek Modu Hata Ayıklayıcısı Nesne Uzantısı

Hata ayıklayıcısı ve hata ayıklayıcı nesneleri, kullanıcı ve çekirdek modunda farklı davranışlara sahiptir. Hata ayıklayıcısı model nesnelerinizi oluştururken, hangi ortamlarda çalışacağınıza karar vermeniz gerekir. COM ile kullanıcı modunda çalışacağız çünkü bu com uzantısını kullanıcı modunda oluşturup test edeceğiz. Diğer durumlarda, hem kullanıcı hem de çekirdek modunda hata ayıklamada çalışacak bir hata ayıklayıcısı JavaScript oluşturabilirsiniz.

Alt Ad Alanı Oluşturma

Örneğimize geri dönüp, bir işlem nesnesine eklemek istediğimiz öğe kümesini içeren bir prototip veya ES6 sınıfı olan comProcessExtension tanımlayabiliriz.

Önemli Alt ad alanının amacı, mantıksal olarak yapılandırılmış ve doğal olarak keşfedilebilir bir paradigma oluşturmaktır. Örneğin, ilişkisiz öğelerin aynı alt ad alanına dökümünü kullanmaktan kaçının. Bir alt ad alanı oluşturmadan önce JavaScript Uzantılarındaki Yerel Hata Ayıklayıcı Nesneleri - Tasarım ve Test Konuları bölümünde açıklanan bilgileri dikkatle gözden geçirin.

Bu kod parçacığında mevcut işlem hata ayıklayıcısı nesnesine 'COM' adlı bir alt ad alanı ekliyoruz.

var comProcessExtension =
{
    //
    // Add a sub-namespace called 'COM' on process.
    //
    get COM()
    {
        //
        // What is 'this' below...?  It's the debugger's process object.  Yes -- this means that there is a cross-language
        // object hierarchy here.  A C++ object implemented in the debugger has a parent model (prototype) which is
        // implemented in JavaScript.
        //
        return new comNamespace(this);
    }
}

Ad Alanı Uygulaması

Ardından, bir işlemde alt ad alanı COM'unu uygulayan nesneyi oluşturun.

Önemli Birden çok işlem olabilir (kullanıcı modunda veya KD altında bu işlemlere bağlı olabilir). Bu uzantı, hata ayıklayıcının mevcut durumunun kullanıcının hedeflediği durum olduğunu varsayamaz. Birisi <bazıProcess>.COM'u bir değişkende yakalayıp değiştirebilir ve bu da yanlış işlem bağlamından bilgi sunulmasına yol açabilir. Çözüm, uzantıya kod ekleyerek her örneklemenin hangi işleme eklendiğini izlemesini sağlamaktır. Bu kod örneği için bu bilgiler özelliğin 'this' işaretçisi aracılığıyla geçirilir.

this.__process = process;

class comNamespace
{
    constructor(process)
    {
        //
        // This is an entirely JavaScript object.  Each instantiation of a comNamespace will keep track
        // of what process it is attached to (passed via the ''this'' pointer of the property getter
        // we authored above.
        //
        this.__process = process;
    }
    
    get GlobalObjects()
    {
        return new globalObjects(this.__process);
    }
}

COM genel arabirim tablosu için uygulama mantığı

COM genel arabirim tablosunun uygulama mantığını daha net bir şekilde ayırmak için iki ES6 sınıfı tanımlayacağız: COM GIP tablosunu soyutlayan gipTable ve yukarıdaki Ad Alanı Uygulama kod parçacığında tanımlanan GlobalObjects() getter'ından döndürülecek olan globalObjects. Bu iç ayrıntıların hata ayıklayıcı ad alanında yayımlanmasını önlemek için bu ayrıntıların tümü initializeScript'in kapatılmasının içinde gizlenebilir.

// gipTable:
//
// Internal class which abstracts away the GIP Table.  It iterates objects of the form
// {entry : GIPEntry, cookie : GIT cookie}
//
class gipTable
{
    constructor(gipProcess)
    {
        //
        // Windows 8 through certain builds of Windows 10, it's in CGIPTable::_palloc.  In certain builds
        // of Windows 10 and later, this has been moved to GIPEntry::_palloc.  We need to check which.
        //
        var gipAllocator = undefined;
        try
        {
            gipAllocator = host.getModuleSymbol("combase.dll", "CGIPTable::_palloc", "CPageAllocator", gipProcess)._pgalloc;
        }
        catch(err)
        {
        }

        if (gipAllocator == undefined)
        {
            gipAllocator = host.getModuleSymbol("combase.dll", "GIPEntry::_palloc", "CPageAllocator", gipProcess)._pgalloc;
        }

        this.__data = {
            process : gipProcess,
            allocator : gipAllocator,
            pageList : gipAllocator._pPageListStart,
            pageCount : gipAllocator._cPages,
            entriesPerPage : gipAllocator._cEntriesPerPage,
            bytesPerEntry : gipAllocator._cbPerEntry,
            PAGESHIFT : 16,
            PAGEMASK : 0x0000FFFF,
            SEQNOMASK : 0xFF00
        };
    }

    *[Symbol.iterator]()
    {
        for (var pageNum = 0; pageNum < this.__data.pageCount; ++pageNum)
        {
            var page = this.__data.pageList[pageNum];
            for (var entryNum = 0; entryNum < this.__data.entriesPerPage; ++entryNum)
            {
                var entryAddress = page.address.add(this.__data.bytesPerEntry * entryNum);
                var gipEntry = host.createPointerObject(entryAddress, "combase.dll", "GIPEntry *", this.__data.process);
                if (gipEntry.cUsage != -1 && gipEntry.dwType != 0)
                {
                    yield {entry : gipEntry, cookie : (gipEntry.dwSeqNo | (pageNum << this.__data.PAGESHIFT) | entryNum)};
                }
            }
        }
    }

    entryFromCookie(cookie)
    {
        var sequenceNo = (cookie & this.__data.SEQNOMASK);
        cookie = cookie & ~sequenceNo;
        var pageNum = (cookie >> this.__data.PAGESHIFT);
        if (pageNum < this.__data.pageCount)
        {
            var page = this.__data.pageList[pageNum];
            var entryNum = (cookie & this.__data.PAGEMASK);
            if (entryNum < this.__data.entriesPerPage)
            {
                var entryAddress = page.address.add(this.__data.bytesPerEntry * entryNum);
                var gipEntry = host.createPointerObject(entryAddress, "combase.dll", "GIPEntry *", this.__data.process);
                if (gipEntry.cUsage != -1 && gipEntry.dwType != 0 && gipEntry.dwSeqNo == sequenceNo)
                {
                    return {entry : gipEntry, cookie : (gipEntry.dwSeqNo | (pageNum << this.__data.PAGESHIFT) | entryNum)};
                }
            }
        }

        //
        // If this exception flows back to C/C++, it will be a failed HRESULT (according to the type of error -- here E_BOUNDS)
        // with the message being encapsulated by an error object.
        //
        throw new RangeError("Unable to find specified value");
    }
}
// globalObjects:
//
// The class which presents how we want the GIP table to look to the data model.  It iterates the actual objects
// in the GIP table indexed by their cookie.
//
class globalObjects
{
    constructor(process)
    {
        this.__gipTable = new gipTable(process);
    }

    *[Symbol.iterator]()
    {
        for (var gipCombo of this.__gipTable)
        {
            yield new host.indexedValue(gipCombo.entry.pUnk, [gipCombo.cookie]);
        }
    }

    getDimensionality()
    {
        return 1;
    }

    getValueAt(cookie)
    {
        return this.__gipTable.entryFromCookie(cookie).entry.pUnk;
    }
}

Son olarak, yeni COM işlevselliğini kaydetmek için host.namedModelRegistration kullanın.

function initializeScript()
{
    return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process"),
            new host.namedModelRegistration(comNamespace, "Debugger.Models.ComProcess")];
}

Not defteri gibi bir uygulama kullanarak kodu GipTableAbstractor.js için kaydedin.

Bu uzantıyı yüklemeden önce kullanıcı modunda kullanılabilen işlem bilgileri aşağıdadır.

0:000:x86> dx @$curprocess
@$curprocess                 : DataBinding.exe
    Name             : DataBinding.exe
    Id               : 0x1b9c
    Threads         
    Modules  

JavaScript uzantısını yükleyin.

0:000:x86> .scriptload C:\JSExtensions\GipTableAbstractor.js
JavaScript script successfully loaded from 'C:\JSExtensions\GipTableAbstractor.js'

Ardından önceden tanımlanmış @$curprocess kullanarak işlem hakkındaki bilgileri görüntülemek için dx komutunu kullanın.

0:000:x86> dx @$curprocess
@$curprocess                 : DataBinding.exe
    Name             : DataBinding.exe
    Id               : 0x1b9c
    Threads         
    Modules         
    COM              : [object Object]
0:000:x86> dx @$curprocess.COM
@$curprocess.COM                 : [object Object]
    GlobalObjects    : [object Object]
0:000:x86> dx @$curprocess.COM.GlobalObjects
@$curprocess.COM.GlobalObjects                 : [object Object]
    [0x100]          : 0x12f4fb0 [Type: IUnknown *]
    [0x201]          : 0x37cfc50 [Type: IUnknown *]
    [0x302]          : 0x37ea910 [Type: IUnknown *]
    [0x403]          : 0x37fcfe0 [Type: IUnknown *]
    [0x504]          : 0x12fe1d0 [Type: IUnknown *]
    [0x605]          : 0x59f04e8 [Type: IUnknown *]
    [0x706]          : 0x59f0eb8 [Type: IUnknown *]
    [0x807]          : 0x59f5550 [Type: IUnknown *]
    [0x908]          : 0x12fe340 [Type: IUnknown *]
    [0xa09]          : 0x5afcb58 [Type: IUnknown *]

Bu tabloya GIT çerezi aracılığıyla programlı olarak da erişilebilir.

0:000:x86> dx @$curprocess.COM.GlobalObjects[0xa09]
@$curprocess.COM.GlobalObjects[0xa09]                 : 0x5afcb58 [Type: IUnknown *]
    [+0x00c] __abi_reference_count [Type: __abi_FTMWeakRefData]
    [+0x014] __capture        [Type: Platform::Details::__abi_CapturePtr]

LINQ ile Hata Ayıklayıcı Nesne Kavramlarını Genişletme

JavaScript, işlem ve iş parçacığı gibi nesneleri genişletebilmenin yanı sıra veri modeliyle ilişkili kavramları da genişletebilir. Örneğin, her yinelenebilir yönteme yeni bir LINQ yöntemi eklemek mümkündür. Her girdiyi yinelenebilir N kez çoğaltan "DuplicateDataModel" adlı örnek bir uzantıyı düşünün. Aşağıdaki kod, bunun nasıl uygulanabileceğini gösterir.

function initializeScript()
{
    var newLinqMethod =
    {
        Duplicate : function *(n)
        {
            for (var val of this)
            {
                for (var i = 0; i < n; ++i)
                {
                    yield val;
                }
            };
        }
    };

    return [new host.namedModelParent(newLinqMethod, "DataModel.Models.Concepts.Iterable")];
}

Not defteri gibi bir uygulama kullanarak kodu DuplicateDataModel.js için kaydedin.

Gerekirse JavaScript betik sağlayıcısını yükleyin ve ardından DuplicateDataModel.js uzantısını yükleyin.

0:000:x86> !load jsprovider.dll
0:000:x86> .scriptload C:\JSExtensions\DuplicateDataModel.js
JavaScript script successfully loaded from 'C:\JSExtensions\DuplicateDataModel.js'

Yeni Yinelenen işlevini test etmek için dx komutunu kullanın.

0: kd> dx -r1 Debugger.Sessions.First().Processes.First().Threads.Duplicate(2),d
Debugger.Sessions.First().Processes.First().Threads.Duplicate(2),d                 : [object Generator]
    [0]              : nt!DbgBreakPointWithStatus (fffff800`9696ca60) 
    [1]              : nt!DbgBreakPointWithStatus (fffff800`9696ca60) 
    [2]              : intelppm!MWaitIdle+0x18 (fffff805`0e351348) 
    [3]              : intelppm!MWaitIdle+0x18 (fffff805`0e351348) 
…

Ayrıca bakınız

JavaScript Uzantılarında Yerel Hata Ayıklayıcı Nesneleri - Hata Ayıklayıcı Nesne Ayrıntıları

JavaScript Uzantılarında Yerel Hata Ayıklayıcı Nesneleri - Tasarım ve Test Konuları

JavaScript Hata Ayıklama Betiği

JavaScript Hata Ayıklayıcısı Örnek Betikleri