
Use Prolog para analisar despejos de memória e processos em execução interrompidos no WinDbg.
Uma extensão WinDbg nativa para x64 e ARM64 com um worker SWI-Prolog persistente. Ela expõe threads, frames de pilha, símbolos, módulos carregados e memória de um dump de modo usuário ou de um processo nativo x64 ou ARM64 parado. Carregue seus próprios arquivos Prolog e execute consultas a partir da janela de comandos do depurador.
Versão: 0.2.0 (experimental; suporte nativo a ARM64).
Use a DLL compilada para a arquitetura do seu depurador. O depurador, a DLL e o
alvo nativo devem corresponder: x64/AMD64 juntos ou ARM64 juntos. Contextos de escopo
entre arquiteturas, WOW64, ARM32 e alvos ARM64EC estão fora do escopo desta versão.
As compilações nativas x64 e ARM64 passaram em todas as 99 verificações portáveis e nos testes
smoke de dump/ao vivo do CDB. Consulte docs/VALIDATION.md para a execução, os logs e as verificações manuais restantes.
O repositório de código-fonte não contém binários compilados. Compile-o usando as
instruções para Windows abaixo para popular dist/x64/ ou dist/arm64/. Os arquivos
de release são nomeados PrologWinDbg-v0.2.0-win-x64.zip e
PrologWinDbg-v0.2.0-win-arm64.zip; cada um coloca seus binários selecionados em dist/.
Os exemplos abaixo usam esse layout do arquivo de release. Para uma compilação a partir do código-fonte,
substitua dist/arm64 ou dist/x64 nos caminhos.
Instale a versão de console para Windows do SWI-Prolog. Instaladores nativos para ARM64 estão disponíveis nos downloads de desenvolvimento. A matriz de CI usa SWI-Prolog nativo 10.1.18-1 em ambas as arquiteturas. O SWI é executado como um processo separado; ele não é vinculado nem incluído na DLL.
Mantenha dist/prolog.dll junto
com os diretórios dist/prolog e dist/examples.
Abra um dump de modo usuário nativo no WinDbg x64 ou ARM64 correspondente, ou anexe a um processo nativo dessa arquitetura e interrompa-o. Para um dump reproduzível, execute isto no PowerShell:
.\dist\prologdbg_target.exe --dump C:\Temp\prologdbg-sample.dmp
No WinDbg, substitua estes caminhos pelo diretório real do seu projeto. Use barras normais em caminhos entre aspas: o depurador trata barras invertidas como escapes.
.load C:/PrologWinDbg/dist/prolog.dll
!prolog.runtime "C:/Program Files/swipl/bin/swipl.exe"
!prolog.info
!prolog.consult "C:/PrologWinDbg/dist/examples/patterns.pl"
!prolog.query wd:current_snapshot(S), wd:architecture(S,Architecture).
!prolog.query wd:current_snapshot(S), wd:thread_id(S,T,WindowsTid).
!prolog.query wd:current_snapshot(S), wd:stack_frame(S,T,Depth,IP).
!prolog.query wd:current_snapshot(S), patterns:stack_contains(S,T,Module,Function).
A extensão usa o caminho de runtime explícito, a variável de ambiente PROLOGDBG_SWIPL, ou a instalação padrão em Program Files\swipl\bin\swipl.exe.
Ela inicia o worker quando necessário pela primeira vez. Toda a comunicação usa pipes locais.
Para o alvo fornecido, inspecione o marcador conhecido de oito bytes:
!prolog.query wd:current_snapshot(S), wd:lookup(S,'prologdbg_target!g_magic',ok(A)), patterns:inspect_magic(S,A,Verdict).
Veredito esperado: matched(prologdb, Address). Os bytes do marcador formam
PROLOGDB. O alvo exporta esses nomes, portanto este exemplo não requer
um PDB. PDBs privados são úteis para outras funções e aplicações.
Inicie prologdbg_target.exe --live no WinDbg. Continue após o breakpoint
inicial do loader. O alvo então para em CapturePoint depois que duas threads
de trabalho foram iniciadas. Use as mesmas consultas usadas para um dump.
Como alternativa, execute prologdbg_target.exe --wait, anexe ao PID impresso
e interrompa. Este modo encerra após dez minutos se não for interrompido antes.
Use os comandos normais do WinDbg bp, g, p e t para controlar a execução. Cada
!prolog.query coleta um novo snapshot. Ações de breakpoint Prolog registradas e
continuação automática estão planejadas para uma versão futura.
| Comando | Finalidade |
|---|---|
!prolog.help | Exibe a ajuda dos comandos |
!prolog.runtime "caminho absoluto para swipl.exe" | Seleciona o runtime e interrompe qualquer worker existente |
!prolog.info | Inicia o worker e informa sua versão |
!prolog.consult "caminho absoluto para rules.pl" | Carrega ou recarrega o código-fonte Prolog |
!prolog.query Goal. | Coleta evidências e enumera soluções |
!prolog.queryfile "caminho absoluto para goal.txt" | Lê um único objetivo UTF-8 de um arquivo e então consulta |
!prolog.eval Goal. | Avalia Prolog sem evidências do depurador |
!prolog.limits | Exibe os limites atuais |
!prolog.limits 5000 100 128 10000000 | Define milissegundos, contagem de respostas, frames por thread e limite de inferências |
!prolog.reset | Interrompe o worker; as regras carregadas e o estado personalizado do runtime são perdidos |
Objetivos simples são passados diretamente após o comando. Aspas simples padrão
do Prolog delimitam átomos. Você pode omitir o ponto final. Use um objetivo por comando,
unindo subobjetivos com vírgulas. Para a disjunção Prolog (;), coloque todo o
objetivo entre aspas duplas para protegê-lo do separador de comandos do WinDbg:
!prolog.eval "(X=a;X=b), writeln(X)."
Para citações complexas, texto Unicode ou objetivos multilinha, coloque o objetivo num ficheiro de texto UTF-8 e use !prolog.queryfile "C:/rules/goal.txt". O seu conteúdo vai diretamente para o Prolog, contornando a análise de texto de comando do WinDbg. O limite do ficheiro é 1 MiB. Para lógica reutilizável, defina predicados num ficheiro .pl consultado.
Exemplo sem um alvo:
!prolog.eval member(X,[1,2,3]), Y is X*X.
As respostas são impressas como bindings([Name=Value, ...], ResidualGoals). A segunda
lista preserva as restrições residuais. Um status final distingue busca esgotada, falha, limites de respostas, limites de inferência, timeouts e exceções.
Atingir um limite de respostas não afirma que existam mais soluções.
Consultar um arquivo executa o carregamento e a inicialização normais do Prolog. Erros de carregamento são reportados, mas o carregamento do Prolog não é transacional: algumas cláusulas podem ter sido carregadas antes de um erro. Corrija e recarregue o arquivo, ou reinicie o worker.
:- module(my_rules, [in_function/4]).
:- use_module('C:/PrologWinDbg/dist/prolog/wd.pl').
in_function(S, T, Module, Function) :-
wd:stack_frame(S, T, _, IP),
wd:symbol(S, IP, Module, Function, _).
Em seguida:
!prolog.consult "C:/rules/my_rules.pl"
!prolog.query wd:current_snapshot(S), my_rules:in_function(S,T,myapp,'ProcessRequest').
Consulte docs/API.md para modos de predicado e semântica de evidências. As regras
iniciais fornecem correspondência de pilha, funções compartilhadas entre threads, evidência
explícita de pilha, endereços ilegíveis e um diagnóstico de assinatura de memória com um
resultado inconclusivo.
O orçamento padrão de consulta é de 5 segundos, 100 respostas, 128 frames por thread e
10 milhões de inferências. A coleta de snapshot recebe seu próprio orçamento de tempo do
mesmo tamanho. O carregamento inicial de símbolos pode ser lento: aqueça o cache de símbolos ou aumente
o primeiro valor com !prolog.limits.
As solicitações de memória são de no máximo 64 KiB cada e 16 MiB no total por consulta. A captura de snapshot é limitada a 4.096 threads, 4.096 módulos carregados e 8 MiB de texto de fatos. O worker usa um limite de pilha Prolog de 512 MiB e um limite de memória de processo do Windows de 768 MiB. A ponte nativa também limita a saída, a contagem de RPC e o tempo de espera de IPC.