Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Nativní objekty ladicího programu představují různé konstrukty a chování prostředí ladicího programu. Objekty lze předat (nebo získat v) javascriptových rozšířeních pro manipulaci se stavem ladicího programu.
Mezi příklady objektů ladicího programu patří následující.
- Sezení
- Vlákna / vlákno
- Procesy / Proces
- Zásobníkové rámce / Zásobníkový rámec
- Místní proměnné
- Moduly / Moduly
- Užitnost
- Stát
- Nastavení
Například host.namespace.Debugger.Utility.Control.ExecuteCommand objekt lze použít k odeslání příkazu u do ladicího programu s následujícími dvěma řádky javascriptového kódu.
var ctl = host.namespace.Debugger.Utility.Control;
var outputLines = ctl.ExecuteCommand("u");
Toto téma popisuje, jak pracovat s běžnými objekty a poskytuje referenční informace o jejich atributech a chování.
Obecné informace o práci s JavaScriptem najdete v tématu Skriptování ladicího programu JavaScriptu. Příklady Jazyka JavaScript, které používají objekty ladicího programu, naleznete v části Ukázkové skripty ladicího programu Jazyka JavaScript. Informace o práci s objekty nastavení naleznete v části .settings (Nastavení ladicích nastavení).
Pokud chcete prozkoumat objekty dostupné v relaci ladicího programu, použijte příkaz dx (Display NatVis Expression). Pomocí tohoto příkazu dx můžete například zobrazit některé objekty ladicího programu nejvyšší úrovně.
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
Všechny výše uvedené položky jsou kliknutelné DML a lze je dále procházet, aby se zobrazila struktura objektu ladicího programu.
Rozšíření ladicího programu prostřednictvím datového modelu
Datový model ladicího programu umožňuje vytvořit rozhraní pro informace o aplikacích a ovladačích ve Windows, které mají následující atributy.
- Je zjistitelný a uspořádaný – logicky strukturovaný prostor názvů lze dotazovat pomocí příkazu dx.
- Lze dotazovat pomocí LINQ- To umožňuje extrakci a řazení dat pomocí standardního dotazovacího jazyka.
- Lze logicky a konzistentně rozšířit – rozšiřitelné pomocí technik popsaných v tomto tématu pomocí zprostředkovatelů skriptování ladicího programu, jako jsou Natvis a JavaScript.
Rozšíření objektu ladicího programu v JavaScriptu
Kromě vytváření vizualizérů v JavaScriptu mohou skriptová rozšíření také upravovat základní koncepty ladicího programu – relace, procesy, vlákna, zásobníky, snímky zásobníku, místní proměnné – a dokonce se publikovat jako rozšiřovací body, které mohou používat další rozšíření.
Tato část popisuje, jak rozšířit základní koncept v rámci ladicího programu. Rozšíření vytvořená tak, aby se sdílela, by měla odpovídat pokynům uvedeným v nativních objektech ladicího programu v rozšířeních JavaScriptu – Aspekty návrhu a testování.
Registrace rozšíření
Skript může zaregistrovat skutečnost, že poskytuje rozšíření jako položku pole vráceného metodou initializeScript.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process")];
}
Přítomnost objektu host.namedModelParent ve vráceném poli oznámí ladicímu programu, že prototyp objektu nebo třída ES6 (v tomto případě comProcessExtension) bude nadřazeným datovým modelem, který je registrován pod názvem Debugger.Models.Process.
Rozšíření objektu debuggeru
Následující body rozšíření ladicího programu jsou nedílnou součástí ladicího programu a jsou k dispozici pro použití poskytovateli skriptů, jako je JavaScript.
Debugger.Models.Sessions: Seznam relací (cílů), ke kterým je ladicí program připojený
Debugger.Models.Session: Jednotlivá relace (cíl), ke které je ladicí program připojený (živý uživatelský režim, KD atd.)
Debugger.Models.Processes: Seznam procesů v rámci relace
Debugger.Models.Threads: Seznam vláken v rámci procesu
Debugger.Models.Thread: Jednotlivé vlákno v rámci procesu (bez ohledu na to, jestli uživatelský nebo režim jádra)
Debugger.Models.Stack: Zásobník vlákna
Debugger.Models.StackFrames: Kolekce rámečků, které tvoří zásobník
Debugger.Models.StackFrame: Samostatný rámec zásobníku v rámci zásobníku
Debugger.Models.LocalVariables: Místní proměnné v zásobníkovém rámci
Debugger.Models.Parameters: Parametry volání v rámci zásobníkového rámce
Debugger.Models.Module: Jednotlivé moduly v adresních prostorech procesu
Další objekty datového modelu
Kromě toho existují další objekty datového modelu, které jsou definované základním datovým modelem.
DataModel.Models.Intrinsic: Vnitřní hodnota (ordinaly, float atd.)
DataModel.Models.String: Řetězec
DataModel.Models.Array: Nativní pole
DataModel.Models.Guid: GUID
DataModel.Models.Error: Objekt chyby
DataModel.Models.Concepts.Iterable: Používá se u každého objektu, který je iterovatelný.
DataModel.Models.Concepts.StringDisplayable: Používá se u každého objektu, který má převod zobrazovaného řetězce.
Přehled rozšíření objektu ladicího programu příkladu COM
Podívejme se na příklad. Představte si, že chcete vytvořit rozšíření ladicího programu pro zobrazení informací specifických pro com, jako je například globální tabulka rozhraní (GIT).
V minulosti mohlo existovat rozšíření ladicího programu s řadou příkazů, které poskytují prostředky pro přístup k informacím o COM. Jeden příkaz může zobrazit informace zaměřené na procesy (například globální tabulka rozhraní). Jiný příkaz může poskytnout informace zaměřené na vlákno, jako je například apartmánový kód, který se spouští uvnitř. Možná budete potřebovat seznámit se s druhým rozšířením ladicího programu a načíst ho, abyste mohli prozkoumat další aspekty modelu COM.
Místo toho, aby byly k dispozici těžko objevitelná příkazy, může rozšíření JavaScriptu změnit pojetí, co je proces a vlákno v ladicím programu, aby tyto informace přidalo způsobem, který je přirozený, přehledný a kombinovatelný s dalšími rozšířeními ladicího programu.
Rozšíření objektu ladicího programu v režimu uživatele nebo jádra
Ladicí program a objekty ladicího programu mají odlišné chování v režimu uživatele a jádra. Při vytváření objektů modelu ladicího programu musíte rozhodnout, ve kterých prostředích budete pracovat. Protože budeme pracovat s modelem COM v uživatelském režimu, vytvoříme a otestujeme toto rozšíření com v uživatelském režimu. V jiných situacích můžete vytvořit ladicí JavaScript, který bude pracovat v uživatelském i kernelovém režimu.
Vytvoření dílčího oboru názvů
Vrátíme se k našemu příkladu, můžeme definovat prototyp nebo třídu ES6 comProcessExtension , která obsahuje sadu věcí, které chceme přidat do objektu procesu.
Důležité Záměrem s podprostorem jmen je vytvořit logicky strukturované a přirozeně prozkoumatelné paradigma. Vyhněte se například dumpingu nesouvisejících položek do stejného dílčího oboru názvů. Pečlivě si projděte informace popisované v nativních objektech ladicího programu v rozšířeních JavaScriptu – Aspekty návrhu a testování před vytvořením dílčího oboru názvů.
V tomto fragmentu kódu vytvoříme do existujícího objektu ladicího programu procesu dílčí obor názvů s názvem COM.
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);
}
}
Implementace oboru názvů
Dále vytvořte objekt, který v procesu implementuje dílčí obor názvů COM.
Důležité V uživatelském režimu nebo pod KD může existovat více procesů (ať už jsou k nim připojeny nebo ne). Toto rozšíření nemůže předpokládat, že současný stav ladicího programu je takový, jaký si uživatel přál. Někdo může zachytit <someProcess>.COM v proměnné a upravit ji, což může vést k prezentaci informací z kontextu nesprávného procesu. Řešením je přidat do rozšíření kód, aby každá instance sledovala, ke kterému procesu je připojený. Pro tento vzorový kód se tyto informace předávají prostřednictvím ukazatele "this" vlastnosti.
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);
}
}
Logika implementace pro tabulku globálního rozhraní modelu COM
Abychom jasněji oddělili logiku implementace pro globální rozhraní tabulky COM, definujeme jednu třídu ES6, gipTable, která abstrahuje tabulku COM GIP, a další globalObjects, což je to, co se vrátí z getteru GlobalObjects() definovaného v části kódu implementace oboru názvů uvedené výše. Všechny tyto podrobnosti mohou být skryty uvnitř blokování funkce initializeScript, aby se zabránilo publikování jakýchkoli z těchto interních podrobností do jmenného prostoru ladicího programu.
// 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;
}
}
Nakonec pomocí host.namedModelRegistration zaregistrujte novou funkci MODELU COM.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process"),
new host.namedModelRegistration(comNamespace, "Debugger.Models.ComProcess")];
}
Uložte kód do GipTableAbstractor.js pomocí aplikace, jako je poznámkový blok.
Tady jsou informace o procesu, které jsou k dispozici v uživatelském režimu před načtením tohoto rozšíření.
0:000:x86> dx @$curprocess
@$curprocess : DataBinding.exe
Name : DataBinding.exe
Id : 0x1b9c
Threads
Modules
Načtěte rozšíření JavaScriptu.
0:000:x86> .scriptload C:\JSExtensions\GipTableAbstractor.js
JavaScript script successfully loaded from 'C:\JSExtensions\GipTableAbstractor.js'
Potom pomocí příkazu dx zobrazte informace o procesu pomocí předdefinované @$curprocess.
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 *]
Tato tabulka je také prostřednictvím kódu programu přístupná prostřednictvím souboru cookie GIT.
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]
Rozšíření konceptů objektů ladicího programu pomocí LINQ
Kromě možnosti rozšířit objekty, jako je proces a vlákno, může JavaScript také rozšířit koncepty spojené s datovým modelem. Můžete například přidat novou metodu LINQ ke každé iterovatelné. Představte si příklad rozšíření "DuplicateDataModel", které duplikuje každou položku v iterovatelném N krát. Následující kód ukazuje, jak to lze implementovat.
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")];
}
Uložte kód do DuplicateDataModel.js pomocí aplikace, jako je poznámkový blok.
V případě potřeby načtěte poskytovatele skriptů JavaScriptu a následně načtěte rozšíření DuplicateDataModel.js.
0:000:x86> !load jsprovider.dll
0:000:x86> .scriptload C:\JSExtensions\DuplicateDataModel.js
JavaScript script successfully loaded from 'C:\JSExtensions\DuplicateDataModel.js'
Pomocí příkazu dx otestujte novou funkci Duplicate.
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)
…
Viz také
Nativní objekty ladicího programu v rozšířeních JavaScriptu – Aspekty návrhu a testování