Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les objets débogueur natifs représentent différentes constructions et comportements de l’environnement du débogueur. Les objets peuvent être transmis à des extensions JavaScript (ou acquis dans celles-ci) pour manipuler l’état du débogueur.
Les exemples d’objets débogueur incluent les éléments suivants.
- session
- Threads / Thread
- Processus / Processus
- Cadres de pile / Cadre de pile
- Variables locales
- Modules / Module
- Utilité
- État
- Paramètres
Par exemple, l’objet host.namespace.Debugger.Utility.Control.ExecuteCommand peut être utilisé pour envoyer la commande u au débogueur avec les deux lignes suivantes du code JavaScript.
var ctl = host.namespace.Debugger.Utility.Control;
var outputLines = ctl.ExecuteCommand("u");
Cette rubrique explique comment utiliser des objets courants et fournit des informations de référence sur leurs attributs et comportements.
Pour obtenir des informations générales sur l’utilisation de JavaScript, consultez Débogueur de scripts JavaScript. Pour obtenir des exemples JavaScript qui utilisent les objets débogueur, consultez les exemples de scripts du débogueur JavaScript. Pour plus d’informations sur l’utilisation des objets de paramètres, consultez .settings (Définir les paramètres de débogage).
Pour explorer les objets disponibles dans une session de débogueur, utilisez la commande dx (Display NatVis Expression). Par exemple, vous pouvez afficher certains objets de débogueur de niveau supérieur avec cette commande dx.
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
Tous les éléments répertoriés ci-dessus sont cliquables dans la DML et peuvent être explorés davantage pour afficher la structure de l'objet du débogueur.
Extension du débogueur via le modèle de données
Le modèle de données du débogueur permet de créer une interface pour obtenir des informations sur les applications et les pilotes dans Windows qui possède les attributs suivants.
- Est détectable et organisé : un espace de nom logiquement structuré peut être interrogé à l’aide de la commande dx.
- Peut être interrogé à l’aide de LINQ- Cela permet l’extraction et le tri de données à l’aide d’un langage de requête standard.
- Peut être étendu de manière logique et cohérente : extensible à l’aide de techniques décrites dans cette rubrique avec des fournisseurs de script de débogueur tels que Natvis et JavaScript.
Extension d’un objet débogueur en JavaScript
En plus de pouvoir créer un visualiseur en JavaScript, les extensions de script peuvent également modifier les concepts fondamentaux du débogueur - sessions, processus, threads, piles, trames de pile, variables locales - et même se publier en tant que points d'extension que d'autres extensions peuvent utiliser.
Cette section explique comment étendre un concept principal au sein du débogueur. Les extensions qui sont générées à partager doivent être conformes aux instructions présentées dans les objets débogueur natifs dans les extensions JavaScript - Considérations relatives à la conception et aux tests.
Inscription d’une extension
Un script peut inscrire le fait qu’il fournit une extension via une entrée dans le tableau retourné par la méthode initializeScript.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process")];
}
La présence d’un objet host.namedModelParent dans le tableau retourné indique au débogueur qu’un objet prototype donné ou une classe ES6 (comProcessExtension dans ce cas) sera un modèle de données parent au modèle inscrit sous le nom Debugger.Models.Process.
Points d’extension d’objet du débogueur
Les points d’extension du débogueur suivants sont intégraux au débogueur et disponibles pour être utilisés par les fournisseurs de script tels que JavaScript.
Débogueur.Models.Sessions : liste des sessions (cibles) auxquelles le débogueur est attaché
Débogueur.Models.Session : session individuelle (cible) à laquelle le débogueur est attaché (mode utilisateur en direct, KD, etc.)
Debugger.Models.Process : liste des processus au sein d’une session
Debugger.Models.Threads : liste de threads au sein d’un processus
Debugger.Models.Thread : thread individuel au sein d’un processus (que ce soit en mode utilisateur ou noyau)
Debugger.Models.Stack : pile d’un thread
Debugger.Models.StackFrames : la collection de frames qui composent une pile
Debugger.Models.StackFrame : trame de pile individuelle dans une pile
Debugger.Models.LocalVariables : les variables locales dans un cadre de pile
Debugger.Models.Parameters : paramètres d’un appel dans une trame de pile
Debugger.Models.Module : module individuel dans l’espace d’adressage d’un processus
Objets de modèle de données supplémentaires
En outre, il existe des objets de modèle de données supplémentaires définis par le modèle de données de base.
DataModel.Models.Intrinsic : une valeur intrinsèque (ordinaux, flottants, etc...).
DataModel.Models.String : chaîne
DataModel.Models.Array : tableau natif
DataModel.Models.Guid : un GUID
DataModel.Models.Error : objet d’erreur
DataModel.Models.Concepts.Iterable : appliqué à chaque objet itérable
DataModel.Models.Concepts.StringDisplayable : appliqué à chaque objet qui a une conversion de chaîne d’affichage
Exemple d’extension d’objet du débogueur COM
Prenons un exemple. Imaginez que vous souhaitez créer une extension de débogueur pour afficher des informations spécifiques à COM, telles que la table d’interface globale (GIT).
Dans le passé, il aurait pu y avoir une extension de débogueur existante avec un certain nombre de commandes qui fournissent un moyen d’accéder à des aspects liés à COM. Une commande peut afficher des informations centrées sur le processus (la table d’interface globale par exemple). Une autre commande peut fournir des informations centrées sur les threads, telles que le code d’appartement en cours d’exécution. Vous devrez peut-être connaître et charger une deuxième extension de débogueur pour explorer d’autres aspects de COM.
Au lieu d’avoir un ensemble de commandes difficiles à découvrir, une extension JavaScript peut modifier le concept du débogueur de ce qu’est un processus et un thread, pour ajouter ces informations d’une manière naturelle, explorable et composable avec d’autres extensions de débogueur.
Extension d’objet du débogueur en mode utilisateur ou noyau
Le débogueur et les objets de débogueur ont un comportement différent en mode utilisateur et noyau. Lorsque vous créez vos objets de modèle de débogueur, vous devez déterminer les environnements dans lesquels vous allez travailler. Étant donné que nous allons travailler avec COM en mode utilisateur, nous allons créer et tester cette extension com en mode utilisateur. Dans d’autres situations, vous pouvez créer un débogueur JavaScript qui fonctionnera à la fois en mode utilisateur et en mode noyau.
Création d’un sous-espace de noms
Retour à notre exemple, nous pouvons définir un prototype ou une classe ES6, comProcessExtension qui contient l’ensemble des éléments que nous voulons ajouter à un objet de processus.
Important L’intention avec l’espace de noms secondaire est de créer un paradigme logiquement structuré et naturellement explorable. Par exemple, évitez de placer des éléments non liés dans le même sous-espace de noms. Examinez attentivement les informations présentées dans les objets débogueur natifs dans les extensions JavaScript - Considérations relatives à la conception et au test avant de créer un sous-espace de noms.
Dans cet extrait de code, nous créons un sous-espace de noms appelé « COM » sur l’objet de débogueur de processus existant.
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);
}
}
Implémentation de l’espace de noms
Ensuite, créez l’objet qui implémente le sous-espace de noms COM sur un processus.
Important Il peut y avoir plusieurs processus (qu’ils soient attachés à ce type en mode utilisateur ou sous KD). Cette extension ne peut pas supposer que l’état actuel du débogueur correspond à ce que l’utilisateur a prévu. Une personne peut capturer <someProcess>.COM dans une variable et la modifier, ce qui peut entraîner la présentation d’informations à partir du contexte de processus incorrect. La solution consiste à ajouter du code dans l’extension afin que chaque instanciation effectue le suivi du processus auquel il est attaché. Pour cet exemple de code, ces informations sont transmises via le pointeur « this » de la propriété.
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);
}
}
Logique d’implémentation pour la table d’interface globale COM
Pour séparer cette logique d’implémentation de la table d’interface globale COM plus clairement, nous allons définir une classe ES6, gipTable qui extrait la table GIP COM et une autre, globalObjects, qui est ce qui sera retourné par le getter GlobalObjects() défini dans le code d’implémentation de l’espace de noms indiqué ci-dessus. Tous ces détails peuvent être encapsulés à l’intérieur de la clôture d'`initializeScript` afin d'éviter la publication de ces détails internes dans l’espace de noms du débogueur.
// 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;
}
}
Enfin, utilisez host.namedModelRegistration pour inscrire la nouvelle fonctionnalité COM.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process"),
new host.namedModelRegistration(comNamespace, "Debugger.Models.ComProcess")];
}
Enregistrez le code dans GipTableAbstractor.js à l’aide d’une application telle que le Bloc-notes.
Voici les informations de processus disponibles en mode utilisateur avant de charger cette extension.
0:000:x86> dx @$curprocess
@$curprocess : DataBinding.exe
Name : DataBinding.exe
Id : 0x1b9c
Threads
Modules
Chargez l’extension JavaScript.
0:000:x86> .scriptload C:\JSExtensions\GipTableAbstractor.js
JavaScript script successfully loaded from 'C:\JSExtensions\GipTableAbstractor.js'
Utilisez ensuite la commande dx pour afficher des informations sur le processus à l’aide du @$curprocess prédéfini.
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 *]
Cette table est également accessible par programmation via le 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]
Extension des concepts d’objet du débogueur avec LINQ
En plus de pouvoir étendre des objets tels que le processus et le thread, JavaScript peut également étendre les concepts associés au modèle de données. Par exemple, il est possible d’ajouter une nouvelle méthode LINQ à chaque itérable. Prenons un exemple d’extension, « DuplicateDataModel » qui duplique chaque entrée dans un nombre N itérable. Le code suivant montre comment cela peut être implémenté.
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")];
}
Enregistrez le code dans DuplicateDataModel.js à l’aide d’une application telle que le Bloc-notes.
Chargez le fournisseur de script JavaScript si nécessaire, puis chargez l’extension 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'
Utilisez la commande dx pour tester la nouvelle fonction dupliquée.
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)
…
Voir aussi
Objets débogueur natifs dans les extensions JavaScript - Détails de l’objet débogueur