windows-nt/Source/XPSP1/NT/base/ntos/config/test/regext.c

592 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
regext.c
Abstract:
Kernel debugger extensions useful for the registry
Author:
John Vert (jvert) 7-Sep-1993
Environment:
Loaded as a kernel debugger extension
Revision History:
John Vert (jvert) 7-Sep-1993
created
--*/
#include "cmp.h"
#include <windef.h>
#include <ntkdexts.h>
#include <stdlib.h>
#include <stdio.h>
HIVE_LIST_ENTRY HiveList[8];
ULONG TotalPages;
ULONG TotalPresentPages;
ULONG TotalKcbs;
ULONG TotalKcbName;
BOOLEAN SavePages;
BOOLEAN RestorePages;
FILE *TempFile;
PNTKD_OUTPUT_ROUTINE lpPrint;
PNTKD_GET_EXPRESSION lpGetExpressionRoutine;
PNTKD_GET_SYMBOL lpGetSymbolRoutine;
PNTKD_CHECK_CONTROL_C lpCheckControlCRoutine;
PNTKD_READ_VIRTUAL_MEMORY lpReadMem;
void
poolDumpHive(
IN PCMHIVE Hive
);
VOID
poolDumpMap(
IN ULONG Length,
IN PHMAP_DIRECTORY Map
);
void
dumpHiveFromFile(
IN FILE *File
);
VOID
kcbWorker(
IN PCM_KEY_CONTROL_BLOCK pKcb
);
VOID
pool(
DWORD dwCurrentPc,
PNTKD_EXTENSION_APIS lpExtensionApis,
LPSTR lpArgumentString
)
/*++
Routine Description:
Goes through all the paged pool allocated to registry space and
determines which pages are present and which are not.
Called as:
!regext.pool [s|r]
s Save list of registry pages to temporary file
r Restore list of registry pages from temp. file
Arguments:
CurrentPc - Supplies the current pc at the time the extension is
called.
lpExtensionApis - Supplies the address of the functions callable
by this extension.
lpArgumentString - Supplies the pattern and expression for this
command.
Return Value:
None.
--*/
{
PLIST_ENTRY pCmpHiveListHead;
PLIST_ENTRY pNextHiveList;
HIVE_LIST_ENTRY *pHiveListEntry;
ULONG BytesRead;
PCMHIVE CmHive;
lpPrint = lpExtensionApis->lpOutputRoutine;
lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine;
lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
lpReadMem = lpExtensionApis->lpReadVirtualMemRoutine;
if (toupper(lpArgumentString[0])=='S') {
SavePages = TRUE;
} else {
SavePages = FALSE;
}
if (toupper(lpArgumentString[0])=='R') {
RestorePages = TRUE;
} else {
RestorePages = FALSE;
}
//
// Go get the hivelist.
//
memset(HiveList,0,sizeof(HiveList));
pHiveListEntry = (PHIVE_LIST_ENTRY)(lpGetExpressionRoutine)("CmpMachineHiveList");
if (pHiveListEntry != NULL) {
(lpReadMem)(pHiveListEntry,
HiveList,
sizeof(HiveList),
&BytesRead);
}
//
// First go and get the hivelisthead
//
pCmpHiveListHead = (PLIST_ENTRY)(lpGetExpressionRoutine)("CmpHiveListHead");
if (pCmpHiveListHead==NULL) {
(lpPrint)("CmpHiveListHead couldn't be read\n");
return;
}
(lpReadMem)(&pCmpHiveListHead->Flink,
&pNextHiveList,
sizeof(pNextHiveList),
&BytesRead);
if (BytesRead != sizeof(pNextHiveList)) {
(lpPrint)("Couldn't read first Flink (%lx) of CmpHiveList\n",
&pCmpHiveListHead->Flink);
return;
}
TotalPages = TotalPresentPages = 0;
if (SavePages) {
TempFile = fopen("regext.dat","w+");
if (TempFile==NULL) {
(lpPrint)("Couldn't create regext.dat for write\n");
return;
}
} else if (RestorePages) {
TempFile = fopen("regext.dat","r");
if (TempFile==NULL) {
(lpPrint)("Couldn't open regext.dat for read\n");
return;
}
}
if (RestorePages) {
dumpHiveFromFile(TempFile);
} else {
while (pNextHiveList != pCmpHiveListHead) {
CmHive = CONTAINING_RECORD(pNextHiveList, CMHIVE, HiveList);
poolDumpHive(CmHive);
(lpReadMem)(&pNextHiveList->Flink,
&pNextHiveList,
sizeof(pNextHiveList),
&BytesRead);
if (BytesRead != sizeof(pNextHiveList)) {
(lpPrint)("Couldn't read Flink (%lx) of %lx\n",
&pCmpHiveListHead->Flink,pNextHiveList);
break;
}
}
}
(lpPrint)("Total pages present = %d / %d\n",
TotalPresentPages,
TotalPages);
if (SavePages || RestorePages) {
fclose(TempFile);
}
}
void
poolDumpHive(
IN PCMHIVE pHive
)
{
CMHIVE CmHive;
ULONG BytesRead;
WCHAR FileName[HBASE_NAME_ALLOC/2 + 1];
ULONG i;
(lpPrint)("\ndumping hive at %lx ",pHive);
(lpReadMem)(pHive,
&CmHive,
sizeof(CmHive),
&BytesRead);
if (BytesRead < sizeof(CmHive)) {
(lpPrint)("\tRead %lx bytes from %lx\n",BytesRead,pHive);
return;
}
(lpReadMem)(&CmHive.Hive.BaseBlock->FileName,
FileName,
sizeof(FileName),
&BytesRead);
if (BytesRead < sizeof(FileName)) {
wcscpy(FileName, L"UNKNOWN");
} else {
if (FileName[0]==L'\0') {
wcscpy(FileName, L"NONAME");
} else {
FileName[HBASE_NAME_ALLOC/2]=L'\0';
}
}
(lpPrint)("(%ws)\n",FileName);
(lpPrint)(" %d KCBs open\n",CmHive.KcbCount);
(lpPrint)(" Stable Length = %lx\n",CmHive.Hive.Storage[Stable].Length);
if (SavePages) {
fprintf(TempFile,
"%ws %d %d\n",
FileName,
CmHive.Hive.Storage[Stable].Length,
CmHive.Hive.Storage[Volatile].Length);
}
poolDumpMap(CmHive.Hive.Storage[Stable].Length,
CmHive.Hive.Storage[Stable].Map);
(lpPrint)(" Volatile Length = %lx\n",CmHive.Hive.Storage[Volatile].Length);
poolDumpMap(CmHive.Hive.Storage[Volatile].Length,
CmHive.Hive.Storage[Volatile].Map);
}
VOID
poolDumpMap(
IN ULONG Length,
IN PHMAP_DIRECTORY Map
)
{
ULONG Tables;
ULONG MapSlots;
ULONG i;
ULONG BytesRead;
HMAP_DIRECTORY MapDirectory;
PHMAP_TABLE MapTable;
HMAP_ENTRY MapEntry;
ULONG Garbage;
ULONG Present=0;
if (Length==0) {
return;
}
MapSlots = Length / HBLOCK_SIZE;
Tables = 1+ ((MapSlots-1) / HTABLE_SLOTS);
//
// read in map directory
//
(lpReadMem)(Map,
&MapDirectory,
Tables * sizeof(PHMAP_TABLE),
&BytesRead);
if (BytesRead < (Tables * sizeof(PHMAP_TABLE))) {
(lpPrint)("Only read %lx/%lx bytes from %lx\n",
BytesRead,
Tables * sizeof(PHMAP_TABLE),
Map);
return;
}
//
// check out each map entry
//
for (i=0; i<MapSlots; i++) {
MapTable = MapDirectory.Directory[i/HTABLE_SLOTS];
(lpReadMem)(&(MapTable->Table[i%HTABLE_SLOTS]),
&MapEntry,
sizeof(HMAP_ENTRY),
&BytesRead);
if (BytesRead < sizeof(HMAP_ENTRY)) {
(lpPrint)(" can't read HMAP_ENTRY at %lx\n",
&(MapTable->Table[i%HTABLE_SLOTS]));
}
if (SavePages) {
fprintf(TempFile, "%lx\n",MapEntry.BlockAddress);
}
//
// probe the HBLOCK
//
(lpReadMem)(MapEntry.BlockAddress,
&Garbage,
sizeof(ULONG),
&BytesRead);
if (BytesRead > 0) {
++Present;
}
}
(lpPrint)(" %d/%d pages present\n",
Present,
MapSlots);
TotalPages += MapSlots;
TotalPresentPages += Present;
}
void
dumpHiveFromFile(
IN FILE *File
)
/*++
Routine Description:
Takes a list of the registry hives and pages from a file and
checks to see how many of the pages are in memory.
The format of the file is as follows
hivename stablelength volatilelength
stable page address
stable page address
.
.
.
volatile page address
volatile page address
.
.
.
hivename stablelength volatilelength
.
.
.
Arguments:
File - Supplies a file.
Return Value:
None.
--*/
{
CHAR Hivename[33];
ULONG StableLength;
ULONG VolatileLength;
ULONG Page;
ULONG i;
ULONG NumFields;
ULONG Garbage;
ULONG Present;
ULONG Total;
ULONG BytesRead;
while (!feof(File)) {
NumFields = fscanf(File,"%s %d %d\n",
Hivename,
&StableLength,
&VolatileLength);
if (NumFields != 3) {
(lpPrint)("fscanf returned %d\n",NumFields);
return;
}
(lpPrint)("\ndumping hive %s\n",Hivename);
(lpPrint)(" Stable Length = %lx\n",StableLength);
Present = 0;
Total = 0;
while (StableLength > 0) {
fscanf(File, "%lx\n",&Page);
(lpReadMem)(Page,
&Garbage,
sizeof(ULONG),
&BytesRead);
if (BytesRead > 0) {
++Present;
}
++Total;
StableLength -= HBLOCK_SIZE;
}
if (Total > 0) {
(lpPrint)(" %d/%d stable pages present\n",
Present,Total);
}
TotalPages += Total;
TotalPresentPages += Present;
(lpPrint)(" Volatile Length = %lx\n",VolatileLength);
Present = 0;
Total = 0;
while (VolatileLength > 0) {
fscanf(File, "%lx\n",&Page);
(lpReadMem)(Page,
&Garbage,
sizeof(ULONG),
&BytesRead);
if (BytesRead > 0) {
++Present;
}
++Total;
VolatileLength -= HBLOCK_SIZE;
}
if (Total > 0) {
(lpPrint)(" %d/%d volatile pages present\n",
Present,Total);
}
TotalPages += Total;
TotalPresentPages += Present;
}
}
void
kcb(
DWORD dwCurrentPc,
PNTKD_EXTENSION_APIS lpExtensionApis,
LPSTR lpArgumentString
)
/*++
Routine Description:
Walks the kcb tree and prints the names of keys which have
outstanding kcbs
Called as:
!regext.kcb
Arguments:
CurrentPc - Supplies the current pc at the time the extension is
called.
lpExtensionApis - Supplies the address of the functions callable
by this extension.
lpArgumentString - Supplies the pattern and expression for this
command.
Return Value:
None.
--*/
{
PCM_KEY_CONTROL_BLOCK pKCB;
PCM_KEY_CONTROL_BLOCK Root;
ULONG BytesRead;
lpPrint = lpExtensionApis->lpOutputRoutine;
lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine;
lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
lpReadMem = lpExtensionApis->lpReadVirtualMemRoutine;
Root = (PCM_KEY_CONTROL_BLOCK)(lpGetExpressionRoutine)("CmpKeyControlBlockRoot");
if (Root == NULL) {
(lpPrint)("Couldn't find address of CmpKeyControlBlockRoot\n");
return;
}
(lpReadMem)(Root,
&pKCB,
sizeof(pKCB),
&BytesRead);
if (BytesRead < sizeof(pKCB)) {
(lpPrint)("Couldn't get pKCB from CmpKeyControlBlockRoot\n");
}
TotalKcbs = 0;
TotalKcbName = 0;
kcbWorker(pKCB);
(lpPrint)("%d KCBs\n",TotalKcbs);
(lpPrint)("%d total bytes of FullNames\n",TotalKcbName);
}
VOID
kcbWorker(
IN PCM_KEY_CONTROL_BLOCK pKcb
)
/*++
Routine Description:
recursive worker for walking the kcb tree.
Arguments:
pKcb - Supplies pointer to kcb.
Return Value:
None.
--*/
{
CM_KEY_CONTROL_BLOCK kcb;
ULONG BytesRead;
WCHAR *Buffer;
++TotalKcbs;
(lpReadMem)(pKcb,
&kcb,
sizeof(kcb),
&BytesRead);
if (BytesRead < sizeof(kcb)) {
(lpPrint)("Can't read kcb at %lx\n",pKcb);
return;
}
TotalKcbName += kcb.FullName.Length;
if (kcb.Left != NULL) {
kcbWorker(kcb.Left);
}
(lpPrint)("%d - ",kcb.RefCount);
Buffer = malloc(kcb.FullName.Length);
if (Buffer != NULL) {
(lpReadMem)(kcb.FullName.Buffer,
Buffer,
kcb.FullName.Length,
&BytesRead);
kcb.FullName.Length = BytesRead;
kcb.FullName.Buffer = Buffer;
(lpPrint)(" %wZ\n",&kcb.FullName);
free(Buffer);
} else {
(lpPrint)(" ??? \n");
}
if (kcb.Right != NULL) {
kcbWorker(kcb.Right);
}
}