34 typedef struct _STRING_TABLE_ENTRY
 
   54 static HANDLE DebugConsoleThreadHandle;
 
   59 static PPH_LIST NewObjectList = NULL;
 
   63 static BOOLEAN ShowAllLeaks = 
FALSE;
 
   64 static BOOLEAN InLeakDetection = 
FALSE;
 
   65 static ULONG NumberOfLeaks;
 
   66 static ULONG NumberOfLeaksShown;
 
   78         menu = GetSystemMenu(GetConsoleWindow(), 
FALSE);
 
   79         EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED);
 
   80         DeleteMenu(menu, SC_CLOSE, 0);
 
   85         freopen(
"CONOUT$", 
"w", stdout);
 
   86         freopen(
"CONOUT$", 
"w", stderr);
 
   87         freopen(
"CONIN$", 
"r", stdin);
 
   94         consoleWindow = GetConsoleWindow();
 
   97         if (IsIconic(consoleWindow))
 
   98             ShowWindow(consoleWindow, SW_RESTORE);
 
  100             BringWindowToTop(consoleWindow);
 
  118     _In_ DWORD dwCtrlType
 
  124     case CTRL_BREAK_EVENT:
 
  125     case CTRL_CLOSE_EVENT:
 
  133 static BOOLEAN NTAPI PhpLoadCurrentProcessSymbolsCallback(
 
  135     _In_opt_ PVOID Context
 
  139         (ULONG64)Module->BaseAddress, Module->Size);
 
  144 static PWSTR PhpGetSymbolForAddress(
 
  149         DebugConsoleSymbolProvider, (ULONG64)Address, NULL, NULL, NULL, NULL
 
  153 static VOID PhpPrintObjectInfo(
 
  155     _In_ 
LONG RefToSubtract
 
  163     wprintf(L
"%Ix", 
object);
 
  166     wprintf(L
"\t% 20s", objectType->
Name);
 
  173     wprintf(L
"\t%4d %c", ObjectHeader->RefCount - RefToSubtract, c);
 
  185         wprintf(L
"\t%.32s", ((
PPH_STRING)
object)->Buffer);
 
  189         wprintf(L
"\t%.32S", ((
PPH_BYTES)
object)->Buffer);
 
  193         wprintf(L
"\tCount: %u", ((
PPH_LIST)
object)->Count);
 
  223 static VOID PhpDumpObjectInfo(
 
  235         wprintf(L
"Type: %s\n", objectType->
Name);
 
  236         wprintf(L
"Reference count: %d\n", ObjectHeader->RefCount);
 
  237         wprintf(L
"Flags: %x\n", ObjectHeader->Flags);
 
  242             wprintf(L
"Number of objects: %u\n", ((
PPH_OBJECT_TYPE)
object)->NumberOfObjects);
 
  245             wprintf(L
"Free list count: %u\n", ((
PPH_OBJECT_TYPE)
object)->FreeList.Count);
 
  249             wprintf(L
"%s\n", ((
PPH_STRING)
object)->Buffer);
 
  253             wprintf(L
"%S\n", ((
PPH_BYTES)
object)->Buffer);
 
  260     __except (EXCEPTION_EXECUTE_HANDLER)
 
  262         wprintf(L
"Error.\n");
 
  271     ULONG expectedLookupMisses = 0;
 
  273     wprintf(L
"Count: %u\n", Hashtable->Count);
 
  274     wprintf(L
"Allocated buckets: %u\n", Hashtable->AllocatedBuckets);
 
  275     wprintf(L
"Allocated entries: %u\n", Hashtable->AllocatedEntries);
 
  276     wprintf(L
"Next free entry: %d\n", Hashtable->FreeEntry);
 
  277     wprintf(L
"Next usable entry: %d\n", Hashtable->NextEntry);
 
  279     wprintf(L
"Hash function: %s\n", PhpGetSymbolForAddress(Hashtable->HashFunction));
 
  280     wprintf(L
"Compare function: %s\n", PhpGetSymbolForAddress(Hashtable->CompareFunction));
 
  282     wprintf(L
"\nBuckets:\n");
 
  284     for (i = 0; i < Hashtable->AllocatedBuckets; i++)
 
  291         index = Hashtable->Buckets[i];
 
  301             expectedLookupMisses += count - 1;
 
  306             wprintf(L
"%lu: ", i);
 
  310             index = Hashtable->Buckets[i];
 
  314                 wprintf(L
"%lu", index);
 
  331     wprintf(L
"\nExpected lookup misses: %lu\n", expectedLookupMisses);
 
  335 static VOID PhpDebugCreateObjectHook(
 
  355 static VOID PhpDeleteNewObjectList(
 
  363         for (i = 0; i < NewObjectList->
Count; i++)
 
  367         NewObjectList = NULL;
 
  372 static BOOLEAN PhpStringHashtableCompareFunction(
 
  383 static ULONG PhpStringHashtableHashFunction(
 
  389     return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length);
 
  392 static int __cdecl PhpStringEntryCompareByCount(
 
  393     _In_ 
const void *elem1,
 
  394     _In_ 
const void *elem2
 
  400     return uintptrcmp(entry2->Count, entry1->Count);
 
  403 static NTSTATUS PhpLeakEnumerationRoutine(
 
  405     _In_ PVOID HeapHandle,
 
  406     _In_ PVOID BaseAddress,
 
  407     _In_ SIZE_T BlockSize,
 
  408     _In_ ULONG StackTraceDepth,
 
  409     _In_ PVOID *StackTrace
 
  414     if (!InLeakDetection)
 
  422         wprintf(L
"Leak at 0x%Ix (%Iu bytes). Stack trace:\n", BaseAddress, BlockSize);
 
  424         for (i = 0; i < StackTraceDepth; i++)
 
  428             symbol = 
PhGetSymbolFromAddress(DebugConsoleSymbolProvider, (ULONG64)StackTrace[i], NULL, NULL, NULL, NULL);
 
  431                 wprintf(L
"\t%s\n", symbol->
Buffer);
 
  438         NumberOfLeaksShown++;
 
  446 typedef struct _STOPWATCH
 
  448     LARGE_INTEGER StartCounter;
 
  449     LARGE_INTEGER EndCounter;
 
  450     LARGE_INTEGER Frequency;
 
  453 static VOID PhInitializeStopwatch(
 
  454     _Out_ PSTOPWATCH Stopwatch
 
  457     Stopwatch->StartCounter.QuadPart = 0;
 
  458     Stopwatch->EndCounter.QuadPart = 0;
 
  461 static VOID PhStartStopwatch(
 
  462     _Inout_ PSTOPWATCH Stopwatch
 
  465     NtQueryPerformanceCounter(&Stopwatch->StartCounter, &Stopwatch->Frequency);
 
  468 static VOID PhStopStopwatch(
 
  469     _Inout_ PSTOPWATCH Stopwatch
 
  472     NtQueryPerformanceCounter(&Stopwatch->EndCounter, NULL);
 
  475 static ULONG PhGetMillisecondsStopwatch(
 
  476     _In_ PSTOPWATCH Stopwatch
 
  479     LARGE_INTEGER countsPerMs;
 
  481     countsPerMs = Stopwatch->Frequency;
 
  482     countsPerMs.QuadPart /= 1000;
 
  484     return (ULONG)((Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart) /
 
  485         countsPerMs.QuadPart);
 
  492 typedef struct _RW_TEST_CONTEXT
 
  505 static LONG RwReadersActive;
 
  506 static LONG RwWritersActive;
 
  508 static NTSTATUS PhpRwLockTestThreadStart(
 
  512 #define RW_ITERS 10000 
  513 #define RW_READ_ITERS 100 
  514 #define RW_WRITE_ITERS 10 
  515 #define RW_READ_SPIN_ITERS 60 
  516 #define RW_WRITE_SPIN_ITERS 200 
  532             context.AcquireShared(context.Parameter);
 
  533             _InterlockedIncrement(&RwReadersActive);
 
  538             if (RwWritersActive != 0)
 
  540                 wprintf(L
"[fail]: writers active in read zone!\n");
 
  541                 NtWaitForSingleObject(NtCurrentProcess(), 
FALSE, NULL);
 
  544             _InterlockedDecrement(&RwReadersActive);
 
  545             context.ReleaseShared(context.Parameter);
 
  549             for (m = 0; m < 10; m++)
 
  552             if (j == RW_READ_ITERS / 2)
 
  558                     context.AcquireExclusive(context.Parameter);
 
  559                     _InterlockedIncrement(&RwWritersActive);
 
  564                     if (RwReadersActive != 0)
 
  566                         wprintf(L
"[fail]: readers active in write zone!\n");
 
  567                         NtWaitForSingleObject(NtCurrentProcess(), 
FALSE, NULL);
 
  570                     _InterlockedDecrement(&RwWritersActive);
 
  571                     context.ReleaseExclusive(context.Parameter);
 
  577     return STATUS_SUCCESS;
 
  580 static VOID PhpTestRwLock(
 
  581     _In_ PRW_TEST_CONTEXT Context
 
  584 #define RW_PROCESSORS 4 
  592     Context->AcquireExclusive(Context->Parameter);
 
  593     Context->ReleaseExclusive(Context->Parameter);
 
  594     Context->AcquireShared(Context->Parameter);
 
  595     Context->ReleaseShared(Context->Parameter);
 
  599     PhStartStopwatch(&stopwatch);
 
  601     for (i = 0; i < 2000000; i++)
 
  603         Context->AcquireExclusive(Context->Parameter);
 
  604         Context->ReleaseExclusive(Context->Parameter);
 
  605         Context->AcquireShared(Context->Parameter);
 
  606         Context->ReleaseShared(Context->Parameter);
 
  609     PhStopStopwatch(&stopwatch);
 
  611     wprintf(L
"[null] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
 
  621         threadHandles[i] = 
PhCreateThread(0, PhpRwLockTestThreadStart, Context);
 
  625     PhStartStopwatch(&stopwatch);
 
  626     NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, 
WaitAll, 
FALSE, NULL);
 
  627     PhStopStopwatch(&stopwatch);
 
  629     for (i = 0; i < RW_PROCESSORS; i++)
 
  630         NtClose(threadHandles[i]);
 
  632     wprintf(L
"[strs] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
 
  684         0, PhpLoadCurrentProcessSymbolsCallback, DebugConsoleSymbolProvider);
 
  688     PhDbgCreateObjectHook = PhpDebugCreateObjectHook;
 
  691     wprintf(L
"Press Ctrl+C or type \"exit\" to close the debug console. Type \"help\" for a list of commands.\n");
 
  695         static PWSTR delims = L
" \t";
 
  696         static PWSTR commandDebugOnly = L
"This command is not available on non-debug builds.\n";
 
  705         if (!fgetws(line, 
sizeof(line) / 2 - 1, stdin))
 
  712         if (inputLength != 0)
 
  713             line[inputLength - 1] = 0;
 
  716         command = wcstok_s(line, delims, &context);
 
  730                 L
"objects [type-name-filter]\n" 
  731                 L
"objtrace object-address\n" 
  745                 L
"enableleakdetect\n" 
  759             RTL_CRITICAL_SECTION testCriticalSection;
 
  768             PhStartStopwatch(&stopwatch);
 
  770             for (i = 0; i < 10000000; i++)
 
  776             PhStopStopwatch(&stopwatch);
 
  779             wprintf(L
"Referencing: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
 
  786             PhStartStopwatch(&stopwatch);
 
  788             for (i = 0; i < 10000000; i++)
 
  794             PhStopStopwatch(&stopwatch);
 
  797             wprintf(L
"Critical section: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
 
  804             PhStartStopwatch(&stopwatch);
 
  806             for (i = 0; i < 10000000; i++)
 
  812             PhStopStopwatch(&stopwatch);
 
  815             wprintf(L
"Fast lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
 
  822             PhStartStopwatch(&stopwatch);
 
  824             for (i = 0; i < 10000000; i++)
 
  830             PhStopStopwatch(&stopwatch);
 
  832             wprintf(L
"Queued lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
 
  839             RTL_CRITICAL_SECTION criticalSection;
 
  841             testContext.Name = L
"FastLock";
 
  846             testContext.Parameter = &fastLock;
 
  848             PhpTestRwLock(&testContext);
 
  851             testContext.Name = L
"QueuedLock";
 
  856             testContext.Parameter = &queuedLock;
 
  858             PhpTestRwLock(&testContext);
 
  860             testContext.Name = L
"CriticalSection";
 
  865             testContext.Parameter = &criticalSection;
 
  867             PhpTestRwLock(&testContext);
 
  870             testContext.Name = L
"QueuedLockMutex";
 
  875             testContext.Parameter = &queuedLock;
 
  877             PhpTestRwLock(&testContext);
 
  882             wprintf(L
"Object small free list count: %u\n", PhObjectSmallFreeList.
Count);
 
  883             wprintf(L
"Statistics:\n");
 
  884 #define PRINT_STATISTIC(Name) wprintf(L#Name L": %u\n", PhLibStatisticsBlock.Name); 
  886             PRINT_STATISTIC(BaseThreadsCreated);
 
  887             PRINT_STATISTIC(BaseThreadsCreateFailed);
 
  888             PRINT_STATISTIC(BaseStringBuildersCreated);
 
  889             PRINT_STATISTIC(BaseStringBuildersResized);
 
  890             PRINT_STATISTIC(RefObjectsCreated);
 
  891             PRINT_STATISTIC(RefObjectsDestroyed);
 
  892             PRINT_STATISTIC(RefObjectsAllocated);
 
  893             PRINT_STATISTIC(RefObjectsFreed);
 
  894             PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList);
 
  895             PRINT_STATISTIC(RefObjectsFreedToSmallFreeList);
 
  896             PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList);
 
  897             PRINT_STATISTIC(RefObjectsFreedToTypeFreeList);
 
  898             PRINT_STATISTIC(RefObjectsDeleteDeferred);
 
  899             PRINT_STATISTIC(RefAutoPoolsCreated);
 
  900             PRINT_STATISTIC(RefAutoPoolsDestroyed);
 
  901             PRINT_STATISTIC(RefAutoPoolsDynamicAllocated);
 
  902             PRINT_STATISTIC(RefAutoPoolsDynamicResized);
 
  903             PRINT_STATISTIC(QlBlockSpins);
 
  904             PRINT_STATISTIC(QlBlockWaits);
 
  905             PRINT_STATISTIC(QlAcquireExclusiveBlocks);
 
  906             PRINT_STATISTIC(QlAcquireSharedBlocks);
 
  907             PRINT_STATISTIC(WqWorkQueueThreadsCreated);
 
  908             PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed);
 
  909             PRINT_STATISTIC(WqWorkItemsQueued);
 
  912             wprintf(commandDebugOnly);
 
  918             PWSTR typeFilter = wcstok_s(NULL, delims, &context);
 
  919             PLIST_ENTRY currentEntry;
 
  920             ULONG totalNumberOfObjects = 0;
 
  928             currentEntry = PhDbgObjectListHead.Flink;
 
  930             while (currentEntry != &PhDbgObjectListHead)
 
  935                 objectHeader = CONTAINING_RECORD(currentEntry, 
PH_OBJECT_HEADER, ObjectListEntry);
 
  940                     currentEntry = currentEntry->Flink;
 
  944                 totalNumberOfObjects++;
 
  955                     (typeFilter && wcsstr(typeName, typeFilter))
 
  958                     PhpPrintObjectInfo(objectHeader, 1);
 
  961                 currentEntry = currentEntry->Flink;
 
  968             wprintf(L
"Total number: %lu\n", totalNumberOfObjects);
 
  971             wprintf(L
"Total overhead (header): %s\n",
 
  976             wprintf(commandDebugOnly);
 
  982             PWSTR objectAddress = wcstok_s(NULL, delims, &context);
 
  988                 wprintf(L
"Missing object address.\n");
 
  997                 PVOID stackBackTrace[16];
 
 1003                     memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * 
sizeof(PVOID));
 
 1005                 __except (EXCEPTION_EXECUTE_HANDLER)
 
 1016                 for (i = 0; i < 16; i++)
 
 1018                     if (!stackBackTrace[i])
 
 1021                     wprintf(L
"%s\n", PhpGetSymbolForAddress(stackBackTrace[i]));
 
 1026                 wprintf(L
"Invalid object address.\n");
 
 1029             wprintf(commandDebugOnly);
 
 1035             PLIST_ENTRY currentEntry;
 
 1037             if (ObjectListSnapshot)
 
 1040                 ObjectListSnapshot = NULL;
 
 1047             currentEntry = PhDbgObjectListHead.Flink;
 
 1049             while (currentEntry != &PhDbgObjectListHead)
 
 1053                 objectHeader = CONTAINING_RECORD(currentEntry, 
PH_OBJECT_HEADER, ObjectListEntry);
 
 1054                 currentEntry = currentEntry->Flink;
 
 1062             wprintf(commandDebugOnly);
 
 1068             PLIST_ENTRY currentEntry;
 
 1072             if (!ObjectListSnapshot)
 
 1074                 wprintf(L
"No snapshot.\n");
 
 1082             currentEntry = PhDbgObjectListHead.Flink;
 
 1084             while (currentEntry != &PhDbgObjectListHead)
 
 1088                 objectHeader = CONTAINING_RECORD(currentEntry, 
PH_OBJECT_HEADER, ObjectListEntry);
 
 1089                 currentEntry = currentEntry->Flink;
 
 1106             for (i = 0; i < newObjects->
Count; i++)
 
 1110                 PhpPrintObjectInfo(objectHeader, 1);
 
 1117             wprintf(commandDebugOnly);
 
 1124             PhpDeleteNewObjectList();
 
 1131             wprintf(commandDebugOnly);
 
 1138             PhpDeleteNewObjectList();
 
 1141             wprintf(commandDebugOnly);
 
 1153                 wprintf(L
"Object creation hooking not active.\n");
 
 1158             for (i = 0; i < NewObjectList->
Count; i++)
 
 1165             wprintf(commandDebugOnly);
 
 1170             PWSTR addressString = wcstok_s(NULL, delims, &context);
 
 1186             PWSTR addressString = wcstok_s(NULL, delims, &context);
 
 1202                     wprintf(L
"Static count: %u\n", userAutoPool->
StaticCount);
 
 1203                     wprintf(L
"Dynamic count: %u\n", userAutoPool->
DynamicCount);
 
 1206                     wprintf(L
"Static objects:\n");
 
 1211                     wprintf(L
"Dynamic objects:\n");
 
 1216                 __except (EXCEPTION_EXECUTE_HANDLER)
 
 1225             PLIST_ENTRY currentEntry;
 
 1229             currentEntry = PhDbgThreadListHead.Flink;
 
 1231             while (currentEntry != &PhDbgThreadListHead)
 
 1233                 PPHP_BASE_THREAD_DBG dbg;
 
 1235                 dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry);
 
 1237                 wprintf(L
"Thread %u\n", (ULONG)dbg->ClientId.UniqueThread);
 
 1238                 wprintf(L
"\tStart Address: %s\n", PhpGetSymbolForAddress(dbg->StartAddress));
 
 1239                 wprintf(L
"\tParameter: %Ix\n", dbg->Parameter);
 
 1240                 wprintf(L
"\tCurrent auto-pool: %Ix\n", dbg->CurrentAutoPool);
 
 1242                 currentEntry = currentEntry->Flink;
 
 1247             wprintf(commandDebugOnly);
 
 1255             if (PhDbgProviderList)
 
 1259                 for (i = 0; i < PhDbgProviderList->Count; i++)
 
 1263                     PLIST_ENTRY providerEntry;
 
 1272                         wprintf(L
"Thread not running\n");
 
 1277                     providerEntry = providerThread->
ListHead.Flink;
 
 1279                     while (providerEntry != &providerThread->
ListHead)
 
 1285                         wprintf(L
"\tProvider registration at %Ix\n", registration);
 
 1286                         wprintf(L
"\t\tEnabled: %s\n", registration->
Enabled ? L
"Yes" : L
"No");
 
 1287                         wprintf(L
"\t\tFunction: %s\n", PhpGetSymbolForAddress(registration->
Function));
 
 1289                         if (registration->
Object)
 
 1291                             wprintf(L
"\t\tObject:\n");
 
 1295                         providerEntry = providerEntry->Flink;
 
 1306             wprintf(commandDebugOnly);
 
 1314             if (PhDbgWorkQueueList)
 
 1318                 for (i = 0; i < PhDbgWorkQueueList->Count; i++)
 
 1321                     PLIST_ENTRY workQueueItemEntry;
 
 1323                     wprintf(L
"Work queue at %s\n", PhpGetSymbolForAddress(workQueue));
 
 1326                     wprintf(L
"No work timeout: %d\n", workQueue->
NoWorkTimeout);
 
 1329                     wprintf(L
"Busy count: %u\n", workQueue->
BusyCount);
 
 1340                         workQueueItem = CONTAINING_RECORD(workQueueItemEntry, 
PH_WORK_QUEUE_ITEM, ListEntry);
 
 1342                         wprintf(L
"\tWork queue item at %Ix\n", workQueueItem);
 
 1343                         wprintf(L
"\t\tFunction: %s\n", PhpGetSymbolForAddress(workQueueItem->
Function));
 
 1344                         wprintf(L
"\t\tContext: %Ix\n", workQueueItem->
Context);
 
 1346                         workQueueItemEntry = workQueueItemEntry->Blink;
 
 1357             wprintf(commandDebugOnly);
 
 1364             SYSTEMTIME systemTime;
 
 1374                 wprintf(L
"Records for %s %s:\n",
 
 1379                 startRecord = record;
 
 1389                 } 
while (record != startRecord);
 
 1399             LONG_PTR processIdFilter = -9; 
 
 1400             ULONG_PTR processAddressFilter = 0;
 
 1401             PWSTR imageNameFilter = NULL;
 
 1402             BOOLEAN showAll = 
FALSE;
 
 1404             ULONG numberOfProcesses;
 
 1407             filterString = wcstok_s(NULL, delims, &context);
 
 1414                     processIdFilter = (LONG_PTR)filter64;
 
 1416                     processAddressFilter = (ULONG_PTR)filter64;
 
 1418                 imageNameFilter = filterString;
 
 1427             for (i = 0; i < numberOfProcesses; i++)
 
 1433                     (processIdFilter != -9 && (LONG_PTR)process->
ProcessId == processIdFilter) ||
 
 1434                     (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) ||
 
 1439                     wprintf(L
"\tRecord at %Ix\n", process->
Record);
 
 1440                     wprintf(L
"\tQuery handle %Ix\n", process->
QueryHandle);
 
 1443                     wprintf(L
"\tFlags: %u\n", process->
Flags);
 
 1453             PLIST_ENTRY currentEntry;
 
 1457             ULONG enumerationKey;
 
 1462                 PhpStringHashtableCompareFunction,
 
 1463                 PhpStringHashtableHashFunction,
 
 1469             currentEntry = PhDbgObjectListHead.Flink;
 
 1471             while (currentEntry != &PhDbgObjectListHead)
 
 1478                 objectHeader = CONTAINING_RECORD(currentEntry, 
PH_OBJECT_HEADER, ObjectListEntry);
 
 1479                 currentEntry = currentEntry->Flink;
 
 1490                 localStringEntry.String = string;
 
 1495                     stringEntry->Count = 1;
 
 1500                     stringEntry->Count++;
 
 1523             for (i = 0; i < 40 && i < list->
Count; i++)
 
 1525                 stringEntry = list->
Items[i];
 
 1526                 wprintf(L
"%Iu\t%.64s\n", stringEntry->Count, stringEntry->String->Buffer);
 
 1529             wprintf(L
"\nTotal unique strings: %u\n", list->
Count);
 
 1533             for (i = 0; i < list->
Count; i++)
 
 1535                 stringEntry = list->
Items[i];
 
 1542             wprintf(commandDebugOnly);
 
 1555                 wprintf(L
"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above.");
 
 1560             VOID (NTAPI *rtlDetectHeapLeaks)(
VOID);
 
 1561             PWSTR options = wcstok_s(NULL, delims, &context);
 
 1565             if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB))
 
 1567                 wprintf(L
"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\n");
 
 1570             ShowAllLeaks = 
FALSE;
 
 1575                     ShowAllLeaks = 
TRUE;
 
 1578             if (rtlDetectHeapLeaks)
 
 1580                 InLeakDetection = 
TRUE;
 
 1582                 NumberOfLeaksShown = 0;
 
 1583                 rtlDetectHeapLeaks();
 
 1584                 InLeakDetection = 
FALSE;
 
 1586                 wprintf(L
"\nNumber of leaks: %lu (%lu displayed)\n", NumberOfLeaks, NumberOfLeaksShown);
 
 1591             PWSTR addressString;
 
 1596             ULONG64 numberOfBytes64;
 
 1598             ULONG numberOfBytes;
 
 1603             addressString = wcstok_s(NULL, delims, &context);
 
 1608             bytesString = wcstok_s(NULL, delims, &context);
 
 1612                 bytesString = L
"16";
 
 1620                 address = (PUCHAR)address64;
 
 1621                 numberOfBytes = (ULONG)numberOfBytes64;
 
 1623                 if (numberOfBytes > 256)
 
 1625                     wprintf(L
"Number of bytes must be 256 or smaller.\n");
 
 1629                 blockSize = 
sizeof(buffer);
 
 1631                 while (numberOfBytes != 0)
 
 1633                     if (blockSize > numberOfBytes)
 
 1634                         blockSize = numberOfBytes;
 
 1638                         memcpy(buffer, address, blockSize);
 
 1640                     __except (EXCEPTION_EXECUTE_HANDLER)
 
 1642                         wprintf(L
"Error reading address near %Ix.\n", address);
 
 1647                     for (i = 0; i < blockSize; i++)
 
 1648                         wprintf(L
"%02x ", buffer[i]);
 
 1651                     for (; i < 
sizeof(buffer); i++)
 
 1657                     for (i = 0; i < blockSize; i++)
 
 1658                         putwchar((ULONG)(buffer[i] - 
' ') <= (ULONG)(
'~' - 
' ') ? buffer[i] : 
'.');
 
 1662                     address += blockSize;
 
 1663                     numberOfBytes -= blockSize;
 
 1669             wprintf(L
"Usage: mem address [numberOfBytes]\n");
 
 1670             wprintf(L
"Example: mem 12345678 16\n");
 
 1674             wprintf(L
"Unrecognized command.\n");
 
 1686     return STATUS_SUCCESS;