/*++ Copyright (c) 1998-2001 Microsoft Corporation Module Name: dbgutil.c Abstract: Utility functions for dealing with the kernel debugger. Author: Keith Moore (keithmo) 17-Jun-1998 Environment: User Mode. Revision History: --*/ #include "precomp.h" // // Private constants. // #define EXT_DLL "kdexts.dll" // // Private globals. // PSTR WeekdayNames[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; PSTR MonthNames[] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; HMODULE ExtensionDll = NULL; // // Public functions. // VOID SystemTimeToString( IN LONGLONG Value, OUT PSTR Buffer ) /*++ Routine Description: Maps a LONGLONG representing system time to a displayable string. Arguments: Value - The LONGLONG time to map. Buffer - Receives the mapped time. Return Value: None. --*/ { NTSTATUS status; LARGE_INTEGER systemTime; LARGE_INTEGER localTime; TIME_FIELDS timeFields; systemTime.QuadPart = Value; status = RtlSystemTimeToLocalTime( &systemTime, &localTime ); if( !NT_SUCCESS(status) ) { sprintf( Buffer, "%I64d", Value ); return; } RtlTimeToTimeFields( &localTime, &timeFields ); sprintf( Buffer, "%s %s %2d %4d %02d:%02d:%02d.%03d", WeekdayNames[timeFields.Weekday], MonthNames[timeFields.Month], timeFields.Day, timeFields.Year, timeFields.Hour, timeFields.Minute, timeFields.Second, timeFields.Milliseconds ); } // SystemTimeToString PSTR SignatureToString( IN ULONG CurrentSignature, IN ULONG ValidSignature, IN ULONG FreedSignature, OUT PSTR Buffer ) { PSTR pstr = Buffer; int i; UCHAR ch; *pstr++ = '\''; for (i = 0; i < 4; ++i) { ch = (UCHAR)((CurrentSignature >> (8 * i)) & 0xFF); *pstr++ = isprint(ch) ? (ch) : '?'; } *pstr++ = '\''; *pstr++ = ' '; *pstr = '\0'; if (CurrentSignature == ValidSignature) { strcat(pstr, "OK"); } else if (CurrentSignature == FreedSignature) { strcat(pstr, "FREED"); } else { strcat(pstr, "INVALID"); } return Buffer; } // SignatureToString PSTR ParseStateToString( IN PARSE_STATE State ) { PSTR result; switch (State) { case ParseVerbState: result = "ParseVerbState"; break; case ParseUrlState: result = "ParseUrlState"; break; case ParseVersionState: result = "ParseVersionState"; break; case ParseHeadersState: result = "ParseHeadersState"; break; case ParseCookState: result = "ParseCookState"; break; case ParseEntityBodyState: result = "ParseEntityBodyState"; break; case ParseTrailerState: result = "ParseTrailerState"; break; case ParseDoneState: result = "ParseDoneState"; break; case ParseErrorState: result = "ParseErrorState"; break; default: result = "INVALID"; break; } return result; } // ParseStateToString PSTR UlEnabledStateToString( IN HTTP_ENABLED_STATE State ) { PSTR result; switch (State) { case HttpEnabledStateActive: result = "HttpEnabledStateActive"; break; case HttpEnabledStateInactive: result = "HttpEnabledStateInactive"; break; default: result = "INVALID"; break; } return result; } PSTR CachePolicyToString( IN HTTP_CACHE_POLICY_TYPE PolicyType ) { PSTR result; switch (PolicyType) { case HttpCachePolicyNocache: result = "HttpCachePolicyNocache"; break; case HttpCachePolicyUserInvalidates: result = "HttpCachePolicyUserInvalidates"; break; case HttpCachePolicyTimeToLive: result = "HttpCachePolicyTimeToLive"; break; default: result = "INVALID"; break; } return result; } PSTR VerbToString( IN HTTP_VERB Verb ) { PSTR result; switch (Verb) { case HttpVerbUnparsed: result = "UnparsedVerb"; break; case HttpVerbGET: result = "GET"; break; case HttpVerbPUT: result = "PUT"; break; case HttpVerbHEAD: result = "HEAD"; break; case HttpVerbPOST: result = "POST"; break; case HttpVerbDELETE: result = "DELETE"; break; case HttpVerbTRACE: result = "TRACE"; break; case HttpVerbOPTIONS: result = "OPTIONS"; break; case HttpVerbCONNECT: result = "CONNECT"; break; case HttpVerbMOVE: result = "MOVE"; break; case HttpVerbCOPY: result = "COPY"; break; case HttpVerbPROPFIND: result = "PROPFIND"; break; case HttpVerbPROPPATCH: result = "PROPPATCH"; break; case HttpVerbMKCOL: result = "MKCOL"; break; case HttpVerbLOCK: result = "LOCK"; break; case HttpVerbUNLOCK: result = "LOCK"; break; case HttpVerbSEARCH: result = "SEARCH"; break; case HttpVerbUnknown: result = "UnknownVerb"; break; case HttpVerbInvalid: result = "InvalidVerb"; break; default: result = "INVALID"; break; } return result; } // VerbToString PSTR VersionToString( IN HTTP_VERSION Version ) { PSTR result; if (HTTP_EQUAL_VERSION(Version, 0, 9)) { result = "Version09"; } else if (HTTP_EQUAL_VERSION(Version, 1, 0)) { result = "Version10"; } else if (HTTP_EQUAL_VERSION(Version, 1, 1)) { result = "Version11"; } else { result = "INVALID"; } return result; } // VersionToString PSTR QueueStateToString( IN QUEUE_STATE QueueState ) { PSTR result; switch (QueueState) { case QueueUnroutedState: result = "QueueUnroutedState"; break; case QueueDeliveredState: result = "QueueDeliveredState"; break; case QueueCopiedState: result = "QueueCopiedState"; break; case QueueUnlinkedState: result = "QueueUnlinkedState"; break; default: result = "INVALID"; break; } return result; } VOID BuildSymbol( IN PVOID RemoteAddress, OUT PSTR Symbol ) { ULONG_PTR offset; CHAR tmpSymbol[MAX_SYMBOL_LENGTH]; tmpSymbol[0] = '\0'; GetSymbol( RemoteAddress, tmpSymbol, &offset ); if (tmpSymbol[0] == '\0') { Symbol[0] = '\0'; } else if (offset == 0) { strcpy( Symbol, (PCHAR)tmpSymbol ); } else { sprintf( Symbol, "%s+0x%p", tmpSymbol, offset ); } } // BuildSymbol PSTR GetSpinlockState( IN PUL_SPIN_LOCK SpinLock ) { if (*((PULONG_PTR)SpinLock) == 0) { return "FREE"; } else { return "ACQUIRED"; } } // GetSpinlockState BOOLEAN EnumLinkedList( IN PLIST_ENTRY RemoteListHead, IN PENUM_LINKED_LIST_CALLBACK Callback, IN PVOID Context ) { LIST_ENTRY localListEntry; PLIST_ENTRY nextRemoteListEntry; ULONG result; // // Try to read the list head. // if (!ReadMemory( (ULONG_PTR)RemoteListHead, &localListEntry, sizeof(localListEntry), &result )) { return FALSE; } // // Loop through the entries. // nextRemoteListEntry = localListEntry.Flink; while (nextRemoteListEntry != RemoteListHead) { if (CheckControlC()) { break; } if (!(Callback)( nextRemoteListEntry, Context )) { break; } if (!ReadMemory( (ULONG_PTR)nextRemoteListEntry, &localListEntry, sizeof(localListEntry), &result )) { return FALSE; } nextRemoteListEntry = localListEntry.Flink; } return TRUE; } // EnumLinkedList BOOLEAN EnumSList( IN PSLIST_HEADER RemoteSListHead, IN PENUM_SLIST_CALLBACK Callback, IN PVOID Context ) { SLIST_HEADER localSListHead; SINGLE_LIST_ENTRY localSListEntry; PSINGLE_LIST_ENTRY nextRemoteSListEntry; ULONG result; // // Try to read the list head. // if (!ReadMemory( (ULONG_PTR)RemoteSListHead, &localSListHead, sizeof(localSListHead), &result )) { return FALSE; } // // Loop through the entries. // nextRemoteSListEntry = SLIST_HEADER_NEXT(&localSListHead); while (nextRemoteSListEntry != NULL) { if (CheckControlC()) { break; } if (!(Callback)( nextRemoteSListEntry, Context )) { break; } if (!ReadMemory( (ULONG_PTR)nextRemoteSListEntry, &localSListEntry, sizeof(localSListEntry), &result )) { return FALSE; } nextRemoteSListEntry = localSListEntry.Next; } return TRUE; } // EnumSList PSTR BuildResourceState( IN PUL_ERESOURCE LocalAddress, OUT PSTR Buffer ) { PERESOURCE pResource; pResource = (PERESOURCE)LocalAddress; if (pResource->ActiveCount == 0) { sprintf( Buffer, "UNOWNED" ); } else { if ((pResource->Flag & ResourceOwnedExclusive) != 0) { sprintf( Buffer, "OWNED EXCLUSIVE BY %p [%ld]", pResource->OwnerThreads[0].OwnerThread, pResource->OwnerThreads[0].OwnerCount ); } else { sprintf( Buffer, "OWNED SHARED" ); } } return Buffer; } // BuildResourceState BOOLEAN IsThisACheckedBuild( VOID ) { ULONG_PTR address; ULONG value = 0; ULONG result; BOOLEAN isChecked = FALSE; address = GetExpression( "&http!g_UlCheckedBuild" ); if (address != 0) { if (ReadMemory( address, &value, sizeof(value), &result )) { isChecked = (value != 0); } } return isChecked; } // IsThisACheckedBuild VOID DumpBitVector( IN PSTR Prefix1, IN PSTR Prefix2, IN ULONG Vector, IN PVECTORMAP VectorMap ) { while ((Vector != 0) && (VectorMap->Vector != 0)) { if (Vector & VectorMap->Vector) { dprintf( "%s%s%s\n", Prefix1, Prefix2, VectorMap->Name ); Vector &= ~(VectorMap->Vector); } VectorMap++; } if (Vector != 0) { dprintf( "%s%sExtra Bits = %08lx\n", Prefix1, Prefix2, Vector ); } } // DumpBitVector VOID DumpRawData( IN PSTR Prefix, IN ULONG_PTR RemoteAddress, IN ULONG BufferLength ) { PSTR lineScan; ULONG lineLength; ULONG i; ULONG result; UCHAR ch; UCHAR rawData[16]; CHAR formattedData[sizeof("1234567812345678 11 22 33 44 55 66 77 88-99 aa bb cc dd ee ff 00 123456789abcdef0")]; while (BufferLength > 0) { lineLength = (BufferLength > 16) ? 16 : BufferLength; if (!ReadMemory( RemoteAddress, rawData, lineLength, &result )) { dprintf( "%sCannot read memory @ %p\n", Prefix, RemoteAddress ); break; } lineScan = formattedData; lineScan += sprintf( lineScan, "%p ", RemoteAddress ); for (i = 0 ; i < 16 ; i++) { if (i < lineLength) { lineScan += sprintf( lineScan, "%02X%c", rawData[i], (i == 7) ? '-' : ' ' ); } else { *lineScan++ = ' '; *lineScan++ = ' '; *lineScan++ = ' '; } } *lineScan++ = ' '; *lineScan++ = ' '; for (i = 0 ; i < 16 ; i++) { if (i < lineLength) { ch = rawData[i]; if ((ch < ' ') || (ch > '~')) { ch = '.'; } } else { ch = ' '; } *lineScan++ = ch; } *lineScan = '\0'; dprintf( "%s%s\n", Prefix, formattedData ); BufferLength -= lineLength; RemoteAddress += (ULONG_PTR)lineLength; } } // DumpRawData BOOLEAN CallExtensionRoutine( IN PSTR RoutineName, IN PSTR ArgumentString ) { #if _WIN64 PWINDBG_EXTENSION_ROUTINE64 ExtRoutine; #else PWINDBG_EXTENSION_ROUTINE ExtRoutine; #endif BOOLEAN result = FALSE; #ifdef EXT_DLL if (ExtensionDll == NULL) { ExtensionDll = LoadLibraryA( EXT_DLL ); } #endif if (ExtensionDll != NULL) { #if _WIN64 ExtRoutine = (PWINDBG_EXTENSION_ROUTINE64)GetProcAddress( ExtensionDll, RoutineName ); #else ExtRoutine = (PWINDBG_EXTENSION_ROUTINE)GetProcAddress( ExtensionDll, RoutineName ); #endif if (ExtRoutine != NULL) { (ExtRoutine)( g_hCurrentProcess, g_hCurrentThread, g_dwCurrentPc, g_dwProcessor, ArgumentString ); result = TRUE; } } return result; } // CallExtensionRoutine