Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Objetos de depurador nativos representam vários constructos e comportamentos do ambiente do depurador. Os objetos podem ser passados em (ou adquiridos em) extensões JavaScript para manipular o estado do depurador.
Os objetos de depurador de exemplo incluem o seguinte.
- Session
- Tarefas/Thread
- Processos/Processo
- Quadros de pilha/quadro de pilha
- Variáveis locais
- Módulos/Módulo
- Utilidade
- Estado
- Configurações
Por exemplo, o objeto host.namespace.Debugger.Utility.Control.ExecuteCommand pode ser usado para enviar o comando u para o depurador com as duas linhas a seguir do código JavaScript.
var ctl = host.namespace.Debugger.Utility.Control;
var outputLines = ctl.ExecuteCommand("u");
Este tópico descreve como trabalhar com objetos comuns e fornece informações de referência sobre seus atributos e comportamentos.
Para obter informações gerais sobre como trabalhar com JavaScript, consulte o Script do Depurador javaScript. Para obter exemplos de JavaScript que usam os objetos do depurador, consulte scripts de exemplo do depurador javaScript. Para obter informações sobre como trabalhar com os objetos de configurações, consulte .settings (Definir configurações de depuração).
Para explorar os objetos disponíveis em uma sessão de depurador, use o comando dx (Exibição de Expressão NatVis). Por exemplo, você pode exibir alguns dos objetos de depurador de nível superior com esse comando 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
Todos os itens listados acima são DML clicáveis e podem ser recursados mais abaixo para exibir a estrutura de objetos do depurador.
Estendendo o depurador por meio do modelo de dados
O modelo de dados do depurador permite a criação de uma interface para informações sobre aplicativos e drivers no Windows que tem os seguintes atributos.
- É detectável e organizado: um espaço de nome estruturado logicamente pode ser consultado usando o comando dx.
- Pode ser consultado usando LINQ- Isso permite extração e classificação de dados usando uma linguagem de consulta padrão.
- Pode ser estendido de maneira lógica e consistente. É extensível usando técnicas descritas neste tópico, com provedores de script para depuradores, como Natvis e JavaScript.
Estendendo um objeto de depurador em JavaScript
Além de poder criar um visualizador em JavaScript, as extensões de script também podem modificar os principais conceitos do depurador - sessões, processos, threads, pilhas, quadros de pilha, variáveis locais - e até mesmo publicar-se como pontos de extensão que outras extensões podem consumir.
Esta seção descreve como estender um conceito fundamental dentro do depurador. As extensões criadas para serem compartilhadas devem estar em conformidade com as diretrizes apresentadas em objetos de depurador nativos em extensões JavaScript – considerações de design e teste.
Registrando uma extensão
Um script pode registrar o fato de que ele fornece uma extensão por meio de uma entrada na matriz retornada do método initializeScript.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process")];
}
A presença de um objeto host.namedModelParent dentro da matriz retornada indica ao depurador que um determinado objeto protótipo ou classe ES6 (comProcessExtension, nesse caso) será um modelo de dados pai para o modelo que é registrado sob o nome Debugger.Models.Process.
Pontos de Extensão do Objeto de Depuração
Os pontos de extensão do depurador a seguir são parte integrante do depurador e estão disponíveis para serem usados por provedores de script, como JavaScript.
Debugger.Models.Sessions: a lista de sessões (destinos) às quais o depurador está anexado
Debugger.Models.Session: uma sessão individual (destino) à qual o depurador está anexado (modo de usuário dinâmico, KD etc...)
Debugger.Models.Processes: a lista de processos em uma sessão
Debugger.Models.Threads: a lista de threads em um processo
Debugger.Models.Thread: um thread individual dentro de um processo (independentemente do modo de usuário ou kernel)
Debugger.Models.Stack: a pilha de um thread
Debugger.Models.StackFrames: a coleção de frames que compõem uma pilha
Debugger.Models.StackFrame: um quadro de pilha individual dentro de uma pilha
Debugger.Models.LocalVariables: as variáveis locais dentro de um frame de pilha
Debugger.Models.Parameters: os parâmetros de uma chamada dentro de um quadro de pilha
Debugger.Models.Module: um módulo individual dentro do espaço de endereço de um processo
Objetos de modelo de dados adicionais
Além disso, há alguns objetos de modelo de dados adicionais definidos pelo modelo de dados principal.
DataModel.Models.Intrinsic: um valor intrínseco (ordinais, pontos flutuantes, etc...)
DataModel.Models.String: uma cadeia de caracteres
DataModel.Models.Array: uma matriz nativa
DataModel.Models.Guid: um Identificador Único Global (GUID)
DataModel.Models.Error: um objeto de erro
DataModel.Models.Concepts.Iterable: aplicado a todos os objetos que podem ser iteráveis
DataModel.Models.Concepts.StringDisplayable: aplicado a cada objeto que tenha uma conversão de cadeia de caracteres de exibição
Visão geral da extensão de objeto de depurador COM de exemplo
Vamos considerar um exemplo. Imagine que você deseja criar uma extensão de depurador para exibir informações específicas do COM, como a tabela de interface global (GIT).
No passado, poderia ter havido uma extensão de depurador existente com vários comandos que forneciam um meio de acessar informações sobre COM. Um comando pode exibir informações centradas no processo (a tabela de interface global, por exemplo). Outro comando pode fornecer informações centradas em thread, como em qual código de apartamento está sendo executado. Pode ser necessário conhecer e carregar uma segunda extensão de depurador para explorar outros aspectos do COM.
Em vez de ter um conjunto de comandos difíceis de descobrir, uma extensão JavaScript pode modificar o conceito do depurador do que é um processo e um thread, para adicionar essas informações de uma maneira natural, explorável e composável com outras extensões de depurador.
Extensão de objeto de depurador do modo de usuário ou kernel
O depurador e os objetos do depurador têm um comportamento diferente no modo de usuário e kernel. Ao criar seus objetos de modelo de depurador, você precisa decidir em quais ambientes você trabalhará. Como trabalharemos com COM no modo de usuário, criaremos e testaremos essa extensão com no modo de usuário. Em outras situações, você poderá criar um JavaScript de debugger que funcionará tanto na depuração do modo de usuário quanto no modo kernel.
Criando um sub-namespace
Voltando ao nosso exemplo, podemos definir um protótipo ou classe ES6, comProcessExtension que contém o conjunto de coisas que queremos adicionar a um objeto de processo.
Importante A intenção com o sub-namespace é criar um paradigma logicamente estruturado e naturalmente explorável. Por exemplo, evite colocar itens não relacionados no mesmo subnamespace. Examine cuidadosamente as informações discutidas em Objetos Nativos do Depurador em Extensões JavaScript – Considerações de Design e Teste antes de criar um subnamespace.
Neste snippet de código, criamos um subnamespace chamado 'COM' no objeto de depurador de processo existente.
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);
}
}
Implementação do namespace
Em seguida, crie o objeto que implementa o subnamespace COM em um processo.
Importante Pode haver vários processos (seja ligados a eles no modo de usuário ou sob KD). Essa extensão não pode assumir que o estado atual do depurador é o que o usuário pretendia. Alguém pode capturar <algumProcess>.COM em uma variável e modificá-lo, o que pode levar à apresentação de informações do contexto de processo errado. A solução é adicionar código na extensão para que cada instanciação acompanhe o processo ao qual está anexada. Para este exemplo de código, esta informação é passada por meio do ponteiro 'this' associado à propriedade.
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);
}
}
Lógica de implementação para a tabela de interface global COM
Para separar essa lógica de implementação para a tabela de interface global COM mais claramente, definiremos uma classe ES6, gipTable que abstrai a tabela COM GIP e outra globalObjects, que é o que será retornado do getter GlobalObjects() definido no snip de código da Implementação do Namespace mostrado acima. Todos esses detalhes podem ser ocultos dentro do fechamento de initializeScript para evitar a publicação de qualquer um desses detalhes internos no namespace do depurador.
// 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;
}
}
Por fim, use host.namedModelRegistration para registrar a nova funcionalidade COM.
function initializeScript()
{
return [new host.namedModelParent(comProcessExtension, "Debugger.Models.Process"),
new host.namedModelRegistration(comNamespace, "Debugger.Models.ComProcess")];
}
Salve o código para GipTableAbstractor.js usando um aplicativo, como o bloco de notas.
Aqui estão as informações do processo disponíveis no modo de usuário antes de carregar essa extensão.
0:000:x86> dx @$curprocess
@$curprocess : DataBinding.exe
Name : DataBinding.exe
Id : 0x1b9c
Threads
Modules
Carregue a extensão JavaScript.
0:000:x86> .scriptload C:\JSExtensions\GipTableAbstractor.js
JavaScript script successfully loaded from 'C:\JSExtensions\GipTableAbstractor.js'
Em seguida, use o comando dx para exibir informações sobre o processo usando o @$curprocess predefinido.
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 *]
Esta tabela também é acessível programaticamente por meio de 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]
Estendendo os conceitos de objetos do Depurador com LINQ
Além de poder estender objetos como processo e thread, o JavaScript também pode estender conceitos associados ao modelo de dados. Por exemplo, é possível adicionar um novo método LINQ a cada iterável. Considere uma extensão de exemplo, "DuplicateDataModel", que duplica cada entrada em um N vezes iterável. O código a seguir mostra como isso pode ser implementado.
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")];
}
Salve o código para DuplicateDataModel.js usando um aplicativo, como o bloco de notas.
Carregue o provedor de scripts JavaScript, se necessário, e carregue a extensão 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'
Use o comando dx para testar a nova função 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)
…
Consulte também
Objetos nativos do depurador em extensões JavaScript – Detalhes do objeto de depurador
Objetos nativos do depurador em extensões JavaScript – Considerações sobre design e teste