Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Собственные объекты отладчика представляют различные конструкции и поведение среды отладчика. Объекты можно передать в расширения 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 — сведения об объекте отладчика