Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Собственные объекты отладчика представляют различные конструкции и поведение среды отладчика. Объекты можно передать в расширения JavaScript или получить из них, чтобы управлять состоянием отладчика.
Ниже приведены примеры объектов отладчика.
- Сессия
- Потоки / поток
- Процессы / Процесс
- Кадры стека и кадр стека
- Локальные переменные
- Модули / модуль
- Полезность
- Государство
- Настройки
Например, объект host.namespace.Debugger.Utility.Control.ExecuteCommand можно использовать для отправки команды u в отладчик со следующими двумя строками кода JavaScript.
var ctl = host.namespace.Debugger.Utility.Control;
var outputLines = ctl.ExecuteCommand("u");
В этом разделе описывается работа с общими объектами и справочные сведения об их атрибутах и поведении.
Общие сведения о работе с JavaScript см. в статье "Скрипт отладчик JavaScript". Примеры JavaScript, использующие объекты отладчика, см. в примерах скриптов отладчика JavaScript. Сведения о работе с объектами параметров см. в разделе .settings (Set Debug Settings).
Чтобы изучить объекты, доступные в сеансе отладчика, используйте команду dx (Display NatVis Expression). Например, можно отобразить некоторые объекты отладчика верхнего уровня с помощью этой команды 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
Все перечисленные выше элементы — это DML с возможностью щелчка, и их можно повторно просмотреть, чтобы просмотреть структуру объектов отладчика.
Расширение отладчика с помощью модели данных
Модель данных отладчика позволяет создавать интерфейс для получения сведений о приложениях и драйверах в Windows, которые имеют следующие атрибуты.
- Доступно для обнаружения и упорядочения— логически структурированное пространство имен можно запрашивать с помощью команды dx.
- Можно запрашивать с помощью LINQ. Это позволяет извлекать и отсортировать данные с помощью стандартного языка запросов.
- Может быть логически и последовательно расширен . Расширяемый с помощью методов, описанных в этом разделе, с поставщиками сценариев отладчика, такими как Natvis и JavaScript.
Расширение объекта отладчика в JavaScript
Помимо возможности создания визуализатора в JavaScript, расширения скриптов также могут изменять основные понятия отладчика — сеансы, процессы, потоки, стеки, кадры стека, локальные переменные и даже публиковать себя в качестве точек расширения, которые могут использовать другие расширения.
В этом разделе описывается расширение основной концепции в отладчике. Расширения, созданные для общего доступа, должны соответствовать рекомендациям, представленным в собственных объектах отладчика в расширениях JavaScript. Рекомендации по проектированию и тестированию.
Регистрация расширения
Скрипт может зарегистрировать тот факт, что он предоставляет расширение через запись в массиве, возвращенную методом initializeScript.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process")];
}
Наличие объекта host.nameModelParent в возвращаемом массиве указывает отладчику, что заданный объект прототипа или класс ES6 (comProcessExtension в этом случае) будет родительской моделью данных, зарегистрированной под именем Debugger.Models.Process.
Точки расширения объектов отладчика
Следующие точки расширения отладчика являются неотъемлемой частью отладчика и доступны для использования поставщиками скриптов, такими как JavaScript.
Debugger.Models.Session: список сеансов (целевых объектов), к которым подключен отладчик.
Debugger.Models.Session: отдельный сеанс (целевой), к которому подключен отладчик (динамический режим пользователя, KD и т. д.)
Debugger.Models.Processes: список процессов в сеансе
Debugger.Models.Threads: список потоков в процессе
Debugger.Models.Thread: отдельный поток в процессе (независимо от того, режим пользователя или ядра)
Отладчик.Models.Stack: стек потока
Debugger.Models.StackFrames: коллекция фреймов, составляющих стек
Debugger.Models.StackFrame: отдельный кадр стека в стеке
Debugger.Models.LocalVariables: локальные переменные в стек вызовов
Debugger.Models.Parameters: параметры для вызова в рамках стекового кадра
Debugger.Models.Module: отдельный модуль в адресном пространстве процесса
Дополнительные объекты модели данных
Кроме того, существуют некоторые дополнительные объекты модели данных, определенные основной моделью данных.
DataModel.Models.Intrinsic: внутреннее значение (порядковые номера, числа с плавающей запятой и т. д.)
DataModel.Models.String: строка
DataModel.Models.Array: собственный массив
DataModel.Models.Guid: GUID
DataModel.Models.Error: объект ошибки
DataModel.Models.Concepts.Iterable: применяется к каждому объекту, который является итерируемым
DataModel.Models.Concepts.StringDisplayable: применяется к каждому объекту, который имеет преобразование строк отображения
Общие сведения о расширении объекта COM-отладчика
Рассмотрим пример. Представьте, что вы хотите создать расширение отладчика для отображения сведений, относящихся к COM, например глобальной таблице интерфейсов (GIT).
В прошлом могло существовать расширение отладчика с некоторыми командами, которые предоставляют средства для доступа к информации о COM. Одна команда может отображать информацию, ориентированную на процесс (например, глобальная таблица интерфейсов). Другая команда может предоставить сведения о потоке, например о том, какой код квартиры выполняется внутри. Для изучения других аспектов COM может потребоваться знать и загрузить второе расширение отладчика.
Вместо того чтобы иметь набор труднодоступных команд, расширение JavaScript может изменить представление отладчика о том, что такое процесс и поток, чтобы добавить эту информацию естественным, интуитивным и сочетающимся с другими расширениями отладчика способом.
Расширение объекта отладчика режима пользователя или ядра
Отладчик и объекты отладчика имеют другое поведение в пользовательском и режиме ядра. При создании объектов модели отладчика необходимо решить, в каких средах вы будете работать. Так как мы будем работать с COM в пользовательском режиме, мы создадим и протестируем это расширение com в пользовательском режиме. В других ситуациях вы можете создать отладчик JavaScript, который будет работать как в режиме пользователя, так и в режиме ядра.
Создание подпространства имен
Возвращаясь к нашему примеру, мы можем определить прототип или класс ES6 comProcessExtension , содержащий набор вещей, которые мы хотим добавить в объект процесса.
Важно Цель подпространства заключается в создании логически структурированной и удобной для исследования парадигмы. Например, избегайте группировки несвязанных элементов в одно и то же подпространство имён. Внимательно изучите информацию, представленную в нативных объектах отладчика в расширениях JavaScript — рекомендации по проектированию и тестированию, перед созданием подпространства имен.
В этом фрагменте кода мы добавляем подпространство имен под названием 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);
}
}
Реализация пространства имен
Затем создайте объект, который реализует подпространство имен COM в процессе.
Важно Может быть несколько процессов (подключенных к ним в пользовательском режиме или в KD). Это расширение не может считать, что текущее состояние отладчика соответствует намерениям пользователя. Кто-то может сохранить <someProcess>.COM в переменной и изменить её, что может привести к представлению информации из неправильного контекста процесса. Решение состоит в добавлении кода в программное расширение, чтобы каждый экземпляр отслеживал процесс, к которому он привязан. В этом примере кода эта информация передается через указатель "this", связанный со свойством.
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
Чтобы более четко разделить логику реализации для таблицы глобальных интерфейсов COM, мы определим один класс ES6, gipTable, который абстрагирует таблицу COM GIP, и другой класс, globalObjects, который будет возвращен из геттера GlobalObjects(), определенного в фрагменте кода реализации пространства имен, показанном выше. Все эти сведения можно скрыть внутри closure функции initialize Script, чтобы не допустить публикацию этих внутренних сведений в пространстве имен отладчика.
// 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;
}
}
Наконец, используйте host.namedModelRegistration для регистрации новых функций COM.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process"),
new host.namedModelRegistration(comNamespace, "Debugger.Models.ComProcess")];
}
Сохраните код для GipTableAbstractor.js с помощью приложения, например блокнота.
Ниже приведены сведения о процессе, доступные в пользовательском режиме перед загрузкой этого расширения.
0:000:x86> dx @$curprocess
@$curprocess : DataBinding.exe
Name : DataBinding.exe
Id : 0x1b9c
Threads
Modules
Загрузите расширение JavaScript.
0:000:x86> .scriptload C:\JSExtensions\GipTableAbstractor.js
JavaScript script successfully loaded from 'C:\JSExtensions\GipTableAbstractor.js'
Затем используйте команду dx для отображения сведений о процессе с помощью предопределенного @$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 *]
Эта таблица также доступна программным способом с помощью файла 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]
Расширение концепций объектов отладчика с помощью LINQ
Помимо возможности расширения объектов, таких как процесс и поток, JavaScript также может расширить понятия, связанные с моделью данных. Например, можно добавить новый метод LINQ к каждому итерируемому методу. Рассмотрим пример расширения "DuplicateDataModel", который дублирует каждую запись в итерируемом N раз. В следующем коде показано, как это можно реализовать.
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")];
}
Сохраните код для DuplicateDataModel.js с помощью приложения, например блокнота.
При необходимости загрузите поставщик скриптов JavaScript, а затем загрузите расширение 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'
Используйте команду dx для проверки новой функции "Дубликат".
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)
…
См. также
Собственные объекты отладчика в расширениях JavaScript — сведения об объекте отладчика