You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
456 lines
13 KiB
456 lines
13 KiB
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <pagemgr.h>
|
|
#include <varobjheap.h>
|
|
#include <sync.h>
|
|
#include <wbemcomn.h>
|
|
|
|
#define MAP_LEADING_SIGNATURE 0xABCD
|
|
#define MAP_TRAILING_SIGNATURE 0xDCBA
|
|
|
|
typedef std::vector <DWORD, wbem_allocator<DWORD> > XFilesMap;
|
|
|
|
DWORD ReadMapFile(const wchar_t *sFilename, XFilesMap &aPageMap, XFilesMap & aPhysFreeList);
|
|
DWORD DumpHeapAdminPages(const wchar_t *sFilename, XFilesMap &aHeapMap, XFilesMap &aHeapFreeList);
|
|
DWORD GetHeapManagedPageCount(const wchar_t *sFilename, XFilesMap &aHeapMap, DWORD &dwNumAdminPages, DWORD &dwNumMultiBlockPages, DWORD &dwNumMultiBlockObjects);
|
|
DWORD GetMapUsageCount(XFilesMap &aHeapMap, DWORD &dwHeapMapUsed, DWORD &dwHeapMapFree);
|
|
DWORD DumpMap(XFilesMap &aMap);
|
|
|
|
|
|
void __cdecl main(int argc, char *argv[ ])
|
|
{
|
|
printf("WMI XFiles repository dumper\n\n");
|
|
bool bDumpHeapAdminPage = false;
|
|
bool bDumpTreeMap = false;
|
|
bool bDumpHeapMap = false;
|
|
|
|
for (int i = 1; i != argc; i++)
|
|
{
|
|
if ((_stricmp(argv[i], "/?") == 0) ||
|
|
(_stricmp(argv[i], "-?") == 0))
|
|
{
|
|
printf("Usage: DumpTool.exe /? - display this message\n"
|
|
" DumpTool.exe /DumpAdminPages - dumps the heap admin tables\n"
|
|
" DumpTool.exe /DumpTreeMap - dumps the tree map usage\n"
|
|
" DumpTool.exe /DumpHeapMap - dumps the heap map usage\n");
|
|
return;
|
|
}
|
|
else if (_stricmp(argv[i], "/DumpAdminPages") == 0)
|
|
{
|
|
bDumpHeapAdminPage = true;
|
|
}
|
|
else if (_stricmp(argv[i], "/DumpTreeMap") == 0)
|
|
{
|
|
bDumpTreeMap = true;
|
|
}
|
|
else if (_stricmp(argv[i], "/DumpHeapMap") == 0)
|
|
{
|
|
bDumpHeapMap = true;
|
|
}
|
|
}
|
|
|
|
DWORD dwRet;
|
|
|
|
XFilesMap aBTreeMap;
|
|
XFilesMap aBTreeFreeList;
|
|
DWORD dwBTreeSize = 0;
|
|
DWORD dwBTreeUsed = 0;
|
|
DWORD dwBTreeFree = 0;
|
|
XFilesMap aHeapMap;
|
|
XFilesMap aHeapFreeList;
|
|
DWORD dwHeapSize = 0;
|
|
DWORD dwHeapUsed = 0;
|
|
DWORD dwHeapFree = 0;
|
|
|
|
//Read MAP Files
|
|
dwRet = ReadMapFile(L"index.map", aBTreeMap, aBTreeFreeList);
|
|
if (dwRet)
|
|
{
|
|
printf("Failed to retrieve index.map details. Please run from within the repository\\fs directory\n");
|
|
return;
|
|
}
|
|
|
|
GetMapUsageCount(aBTreeMap, dwBTreeUsed, dwBTreeFree);
|
|
|
|
dwRet = ReadMapFile(L"objects.map", aHeapMap, aHeapFreeList);
|
|
if (dwRet)
|
|
{
|
|
printf("Failed to retrieve objects.map details. Please run from within the repository\\fs directory\n");
|
|
return;
|
|
}
|
|
|
|
GetMapUsageCount(aHeapMap, dwHeapUsed, dwHeapFree);
|
|
|
|
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
|
|
dwRet = GetFileAttributesEx(L"INDEX.BTR", GetFileExInfoStandard, &fileInfo);
|
|
if (dwRet == 0)
|
|
{
|
|
printf("Failed to retrieve size of index.btr file\n");
|
|
return;
|
|
}
|
|
dwBTreeSize = fileInfo.nFileSizeLow / WMIREP_PAGE_SIZE;
|
|
|
|
dwRet = GetFileAttributesEx(L"OBJECTS.DATA", GetFileExInfoStandard, &fileInfo);
|
|
if (dwRet == 0)
|
|
{
|
|
printf("Failed to retrieve size of objects.data file\n");
|
|
return;
|
|
}
|
|
dwHeapSize = fileInfo.nFileSizeLow / WMIREP_PAGE_SIZE;
|
|
|
|
//Dump MAP file usage and free space sumary
|
|
printf("BTree has %lu pages in it, of which %lu pages are in use and %lu pages are free\n",
|
|
dwBTreeSize, dwBTreeUsed, dwBTreeSize - dwBTreeUsed);
|
|
printf("Heap has %lu pages in it, of which %lu pages are in use and %lu pages are free\n",
|
|
dwHeapSize, dwHeapUsed, dwHeapSize - dwHeapUsed);
|
|
|
|
//Get number of managed pages for heap...
|
|
DWORD dwNumAdminPages = 0;
|
|
DWORD dwNumMultiBlockPages = 0;
|
|
DWORD dwNumMultiBlockObjects = 0;
|
|
dwRet = GetHeapManagedPageCount(L"OBJECTS.DATA", aHeapMap, dwNumAdminPages, dwNumMultiBlockPages, dwNumMultiBlockObjects);
|
|
if (dwRet)
|
|
{
|
|
printf("Failed to retrieve number of pages used in object heap\n");
|
|
return;
|
|
}
|
|
|
|
printf("Heap has %lu admin pages, \n\t%lu pages used for small block allocation, total of %lu small block allocations, \n\t%lu pages for large block allocations\n",
|
|
dwNumAdminPages,
|
|
dwNumMultiBlockPages,
|
|
dwNumMultiBlockObjects,
|
|
dwHeapSize - (dwHeapSize - dwHeapUsed) - dwNumAdminPages - dwNumMultiBlockPages);
|
|
|
|
if (bDumpHeapAdminPage)
|
|
{
|
|
dwRet = DumpHeapAdminPages(L"OBJECTS.DATA", aHeapMap, aHeapFreeList);
|
|
if (dwRet)
|
|
{
|
|
printf("Failed to dump the admin pages in the heap\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (bDumpTreeMap)
|
|
{
|
|
printf("**** BTree MAP Usage ****\n");
|
|
DumpMap(aBTreeMap);
|
|
}
|
|
|
|
if (bDumpHeapMap)
|
|
{
|
|
printf("**** Heap MAP Usage ****\n");
|
|
DumpMap(aHeapMap);
|
|
}
|
|
|
|
}
|
|
|
|
DWORD ReadMapFile(const wchar_t *sFilename, XFilesMap &aPageMap,XFilesMap & aPhysFreeList)
|
|
{
|
|
BOOL bRes;
|
|
|
|
HANDLE hFile = CreateFileW(sFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwRet = GetLastError();
|
|
return dwRet;
|
|
}
|
|
|
|
AutoClose _(hFile);
|
|
|
|
// If here, read it.
|
|
// =================
|
|
|
|
DWORD dwSignature = 0;
|
|
DWORD dwRead = 0;
|
|
|
|
bRes = ReadFile(hFile, &dwSignature, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD) || dwSignature != MAP_LEADING_SIGNATURE)
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
// Read transaction version.
|
|
// =========================
|
|
|
|
DWORD dwTransVersion;
|
|
bRes = ReadFile(hFile, &dwTransVersion, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD))
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
// Read in physical page count.
|
|
// ============================
|
|
DWORD dwPhysPages;
|
|
bRes = ReadFile(hFile, &dwPhysPages, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD))
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
// Read in the page map length and page map.
|
|
// =========================================
|
|
|
|
DWORD dwNumPages = 0;
|
|
bRes = ReadFile(hFile, &dwNumPages, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD))
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
try
|
|
{
|
|
aPageMap.resize(dwNumPages);
|
|
}
|
|
catch (CX_MemoryException &)
|
|
{
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
bRes = ReadFile(hFile, &aPageMap[0], sizeof(DWORD)*dwNumPages, &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD)*dwNumPages)
|
|
return ERROR_INVALID_DATA;
|
|
|
|
// Now, read in the physical free list.
|
|
// ====================================
|
|
|
|
DWORD dwFreeListSize = 0;
|
|
bRes = ReadFile(hFile, &dwFreeListSize, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD))
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
try
|
|
{
|
|
aPhysFreeList.resize(dwFreeListSize);
|
|
}
|
|
catch (CX_MemoryException &)
|
|
{
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
bRes = ReadFile(hFile, &aPhysFreeList[0], sizeof(DWORD)*dwFreeListSize, &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD)*dwFreeListSize)
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
// Read trailing signature.
|
|
// ========================
|
|
|
|
bRes = ReadFile(hFile, &dwSignature, sizeof(DWORD), &dwRead, 0);
|
|
if (!bRes || dwRead != sizeof(DWORD) || dwSignature != MAP_TRAILING_SIGNATURE)
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD DumpHeapAdminPages(const wchar_t *sFilename, XFilesMap &aHeapMap, XFilesMap &aHeapFreeList)
|
|
{
|
|
//Open the file...
|
|
HANDLE hFile = CreateFile(sFilename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return GetLastError();
|
|
|
|
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
if (hMapping == NULL)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
CloseHandle(hFile);
|
|
return dwErr;
|
|
}
|
|
|
|
BYTE *pObj = (BYTE *)MapViewOfFile(hMapping, FILE_MAP_READ, 0,0,0);
|
|
if (pObj == NULL)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hFile);
|
|
return dwErr;;
|
|
}
|
|
|
|
//Do stuff...
|
|
DWORD dwVirtualPageId = 0;
|
|
DWORD dwTotalObjectCount = 0;
|
|
|
|
printf("Heap admin page dump...\n");
|
|
do
|
|
{
|
|
DWORD dwPhysicalPageId = aHeapMap[dwVirtualPageId];
|
|
VarObjHeapAdminPage *pAdminPageHeader = (VarObjHeapAdminPage *)(pObj + (dwPhysicalPageId * WMIREP_PAGE_SIZE));
|
|
VarObjHeapFreeList *pAdminPageEntry = (VarObjHeapFreeList *)((BYTE*)pAdminPageHeader + sizeof(VarObjHeapAdminPage));
|
|
|
|
printf("Admin page %lu (physical page %lu): number of page entries %lu\n", dwVirtualPageId, dwPhysicalPageId, pAdminPageHeader->dwNumberEntriesOnPage);
|
|
|
|
for (DWORD dwIndex = 0; dwIndex != pAdminPageHeader->dwNumberEntriesOnPage; dwIndex++)
|
|
{
|
|
DWORD dwNumObjectsOnPage = 0;
|
|
VarObjObjOffsetEntry *pObjPage = (VarObjObjOffsetEntry*)(pObj + (aHeapMap[pAdminPageEntry[dwIndex].dwPageId] * WMIREP_PAGE_SIZE));
|
|
for (DWORD dwIndex2 = 0; pObjPage[dwIndex2].dwOffsetId != 0; dwIndex2++)
|
|
{
|
|
dwNumObjectsOnPage++;
|
|
}
|
|
printf("\tPage % 6lu (physical page % 6lu): %4lu bytes free (% 2lu%%), %4lu objects on page\n",
|
|
pAdminPageEntry[dwIndex].dwPageId,
|
|
aHeapMap[pAdminPageEntry[dwIndex].dwPageId],
|
|
pAdminPageEntry[dwIndex].dwFreeSpace,
|
|
(pAdminPageEntry[dwIndex].dwFreeSpace * 100) / WMIREP_PAGE_SIZE,
|
|
dwNumObjectsOnPage);
|
|
}
|
|
|
|
dwVirtualPageId = pAdminPageHeader->dwNextAdminPage;
|
|
} while (dwVirtualPageId != 0);
|
|
|
|
//Tidy up
|
|
UnmapViewOfFile(pObj);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hFile);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
DWORD GetHeapManagedPageCount(const wchar_t *sFilename, XFilesMap &aHeapMap, DWORD &dwNumAdminPages, DWORD &dwNumMultiBlockPages, DWORD &dwNumMultiBlockObjects)
|
|
{
|
|
//Open the file...
|
|
HANDLE hFile = CreateFile(sFilename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return GetLastError();
|
|
|
|
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
if (hMapping == NULL)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
CloseHandle(hFile);
|
|
return dwErr;
|
|
}
|
|
|
|
BYTE *pObj = (BYTE *)MapViewOfFile(hMapping, FILE_MAP_READ, 0,0,0);
|
|
if (pObj == NULL)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hFile);
|
|
return dwErr;;
|
|
}
|
|
|
|
//Do stuff...
|
|
DWORD dwVirtualPageId = 0;
|
|
|
|
do
|
|
{
|
|
dwNumAdminPages++;
|
|
DWORD dwPhysicalPageId = aHeapMap[dwVirtualPageId];
|
|
VarObjHeapAdminPage *pAdminPageHeader = (VarObjHeapAdminPage *)(pObj + (dwPhysicalPageId * WMIREP_PAGE_SIZE));
|
|
VarObjHeapFreeList *pAdminPageEntry = (VarObjHeapFreeList *)((BYTE*)pAdminPageHeader + sizeof(VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwIndex = 0; dwIndex != pAdminPageHeader->dwNumberEntriesOnPage; dwIndex++)
|
|
{
|
|
dwNumMultiBlockPages++;
|
|
DWORD dwNumObjectsOnPage = 0;
|
|
VarObjObjOffsetEntry *pObjPage = (VarObjObjOffsetEntry*)(pObj + (aHeapMap[pAdminPageEntry[dwIndex].dwPageId] * WMIREP_PAGE_SIZE));
|
|
for (DWORD dwIndex2 = 0; pObjPage[dwIndex2].dwOffsetId != 0; dwIndex2++)
|
|
{
|
|
dwNumMultiBlockObjects++;
|
|
}
|
|
}
|
|
|
|
dwVirtualPageId = pAdminPageHeader->dwNextAdminPage;
|
|
} while (dwVirtualPageId != 0);
|
|
|
|
//Tidy up
|
|
UnmapViewOfFile(pObj);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hFile);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
DWORD GetMapUsageCount(XFilesMap &aMap, DWORD &dwMapUsed, DWORD &dwMapFree)
|
|
{
|
|
for (DWORD i = 0; i < aMap.size(); i++)
|
|
{
|
|
if (aMap[i] == WMIREP_INVALID_PAGE)
|
|
dwMapFree++;
|
|
else
|
|
dwMapUsed++;
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
void ShellSort(XFilesMap &Array)
|
|
{
|
|
for (int nInterval = 1; nInterval < Array.size() / 9; nInterval = nInterval * 3 + 1);
|
|
|
|
while (nInterval)
|
|
{
|
|
for (int iCursor = nInterval; iCursor < Array.size(); iCursor++)
|
|
{
|
|
int iBackscan = iCursor;
|
|
while (iBackscan - nInterval >= 0 && Array[iBackscan] < Array[iBackscan-nInterval])
|
|
{
|
|
DWORD dwTemp = Array[iBackscan-nInterval];
|
|
Array[iBackscan-nInterval] = Array[iBackscan];
|
|
Array[iBackscan] = dwTemp;
|
|
iBackscan -= nInterval;
|
|
}
|
|
}
|
|
nInterval /= 3;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD DumpMap(XFilesMap &aMap)
|
|
{
|
|
//Need to sort it... and need our own copy...
|
|
XFilesMap aNewMap = aMap;
|
|
ShellSort(aNewMap);
|
|
|
|
printf("**** Usage dump... **** \n");
|
|
DWORD dwStartId = aNewMap[0];
|
|
for (DWORD dwOffset = 1; dwOffset < aNewMap.size(); dwOffset++)
|
|
{
|
|
if (dwStartId == 0xFFFFFFFF)
|
|
break;
|
|
|
|
//Work up to the end of this run
|
|
for (DWORD dwCurrentRun = 1; (dwStartId+dwCurrentRun) == aNewMap[dwOffset]; dwOffset++, dwCurrentRun++)
|
|
{
|
|
}
|
|
|
|
//Finished slot... dump usage use
|
|
if (dwStartId == aNewMap[dwOffset-1])
|
|
{
|
|
//Single location slot...
|
|
printf("% 6lu Used\n", dwStartId);
|
|
}
|
|
else
|
|
{
|
|
//Multiple location slot...
|
|
printf("% 6lu - % 6lu Used\n", dwStartId, aNewMap[dwOffset-1]);
|
|
}
|
|
|
|
if (dwOffset+1 <= aNewMap.size())
|
|
{
|
|
//Dump free space usage now
|
|
if (aNewMap[dwOffset-1]+1 == aNewMap[dwOffset]-1)
|
|
{
|
|
//Single location slot...
|
|
printf("% 6lu Free\n", aNewMap[dwOffset-1]+1);
|
|
}
|
|
else
|
|
{
|
|
//Multiple location slot...
|
|
printf("% 6lu - % 6lu Free\n", aNewMap[dwOffset-1]+1, aNewMap[dwOffset]-1);
|
|
}
|
|
dwStartId = aNewMap[dwOffset];
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|