/*++ Copyright (c) 1995-1998 Microsoft Corporation Module Name: strlog.cxx Abstract: CStringTraceLog support Author: George V. Reilly (GeorgeRe) 22-Jun-1998 Revision History: --*/ #include "inetdbgp.h" /************************************************************ * Dump String Trace Logs ************************************************************/ // Dummy implementations so that we can link CStringTraceLog::CStringTraceLog( UINT cchEntrySize /* = 80 */, UINT cLogSize /* = 100 */) {} CStringTraceLog::~CStringTraceLog() {} VOID DumpStringTraceLog( IN PSTR lpArgumentString, IN BOOLEAN fReverse ) /*++ Routine Description: Dumps the specified print trace log either forwards (fReverse == FALSE) or backwards (fReverse == TRUE). Arguments: lpArgumentString - An expression specifying the print trace log to dump. fReverse - The dump direction. Return Value: None. --*/ { ULONG_PTR stlLogAddress = 0; ULONG_PTR entryAddress; LONG numEntries; CStringTraceLog stlHeader; TRACE_LOG tlogHeader; CStringTraceLog::CLogEntry logEntry; LONG i; DWORD offset; PCHAR format; LONG index; LONG direction; PSTR cmdName; UCHAR symbol[MAX_PATH]; INT nVerbose = 0; direction = fReverse ? -1 : 1; cmdName = fReverse ? "rst" : "st"; // // Skip leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { PrintUsage( cmdName ); return; } if ( *lpArgumentString == '-' ) { lpArgumentString++; if ( *lpArgumentString == 'h' ) { PrintUsage( cmdName ); return; } if ( *lpArgumentString == 'l' ) { lpArgumentString++; if ('0' <= *lpArgumentString && *lpArgumentString <= '9' ) { nVerbose = *lpArgumentString++ - '0'; } } } while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } stlLogAddress = (ULONG_PTR)GetExpression( lpArgumentString ); if( stlLogAddress == 0 ) { dprintf( "inetdbg.%s: cannot evaluate \"%s\"\n", cmdName, lpArgumentString ); return; } // // Skip to end of expression, then skip any blanks. // while( *lpArgumentString != ' ' && *lpArgumentString != '\t' && *lpArgumentString != '\0' ) { lpArgumentString++; } // // Read the log header, perform some sanity checks. // if( !ReadMemory( stlLogAddress, &stlHeader, sizeof(stlHeader), NULL ) ) { dprintf( "inetdbg.%s: cannot read memory @ %p\n", cmdName, (PVOID)stlLogAddress ); return; } if( !ReadMemory( stlHeader.m_ptlog, &tlogHeader, sizeof(tlogHeader), NULL ) ) { dprintf( "inetdbg.%s: cannot read tracelog memory @ %p\n", cmdName, (PVOID)stlHeader.m_ptlog ); return; } dprintf( "inetdbg.%s: log @ %p:\n" " String Trace Log Signature = %08lx (%s)\n" " Trace Log Signature = %08lx (%s)\n" " LogSize = %lu\n" " NextEntry = %lu\n" " EntrySize = %lu\n" " LogBuffer = %p\n", cmdName, (PVOID)stlLogAddress, stlHeader.m_Signature, stlHeader.m_Signature == CStringTraceLog::SIGNATURE ? "OK" : stlHeader.m_Signature == CStringTraceLog::SIGNATURE_X ? "FREED" : "INVALID", tlogHeader.Signature, tlogHeader.Signature == TRACE_LOG_SIGNATURE ? "OK" : tlogHeader.Signature == TRACE_LOG_SIGNATURE_X ? "FREED" : "INVALID", tlogHeader.LogSize, tlogHeader.NextEntry, tlogHeader.EntrySize, tlogHeader.LogBuffer ); if( tlogHeader.LogBuffer > ( (PUCHAR)stlHeader.m_ptlog + sizeof(tlogHeader) ) ) { dprintf( " Extra Data @ %p\n", (PVOID)( stlLogAddress + sizeof(tlogHeader) ) ); } if( stlHeader.m_Signature != CStringTraceLog::SIGNATURE && stlHeader.m_Signature != CStringTraceLog::SIGNATURE_X ) { dprintf( "inetdbg.%s: log @ %p has invalid signature: %08lx\n", cmdName, (PVOID)stlLogAddress, stlHeader.m_Signature ); return; } if( (UINT) tlogHeader.EntrySize != sizeof(CStringTraceLog::CLogEntry) - CStringTraceLog::MAX_CCH + stlHeader.m_cch ) { dprintf( "inetdbg.%s: log @ %p is not a print trace log\n", cmdName, (PVOID)stlLogAddress ); return; } if( tlogHeader.NextEntry == -1 ) { dprintf( "inetdbg.%s: empty log @ %p\n", cmdName, (PVOID)stlLogAddress ); return; } // // Calculate the starting address and number of entries. // if( fReverse ) { if( tlogHeader.NextEntry < tlogHeader.LogSize ) { numEntries = tlogHeader.NextEntry + 1; index = tlogHeader.NextEntry; } else { numEntries = tlogHeader.LogSize; index = tlogHeader.NextEntry % tlogHeader.LogSize; } } else { if( tlogHeader.NextEntry < tlogHeader.LogSize ) { numEntries = tlogHeader.NextEntry + 1; index = 0; } else { numEntries = tlogHeader.LogSize; index = ( tlogHeader.NextEntry + 1 ) % tlogHeader.LogSize; } } entryAddress = (ULONG_PTR)tlogHeader.LogBuffer + (ULONG_PTR)( index * tlogHeader.EntrySize ); if( entryAddress >= ( (ULONG_PTR)tlogHeader.LogBuffer + (ULONG_PTR)( numEntries * tlogHeader.EntrySize ) ) ) { dprintf( "inetdbg.%s: log @ %p has invalid data\n", cmdName, (PVOID)stlLogAddress ); return; } // // Dump the log, which is stored in a circular buffer. // for( ; numEntries > 0 ; index += direction, numEntries--, entryAddress += ( direction * tlogHeader.EntrySize ) ) { if( CheckControlC() ) { break; } if( index >= tlogHeader.LogSize ) { index = 0; entryAddress = (ULONG_PTR)tlogHeader.LogBuffer; } else if( index < 0 ) { index = tlogHeader.LogSize - 1; entryAddress = (ULONG_PTR)tlogHeader.LogBuffer + (ULONG_PTR)( index * tlogHeader.EntrySize ); } if( !ReadMemory( entryAddress, &logEntry, tlogHeader.EntrySize, NULL ) ) { dprintf( "inetdbg.%s: cannot read memory @ %p\n", cmdName, (ULONG_PTR)entryAddress ); return; } if (nVerbose == 0) { dprintf( "%04x: %s\n", logEntry.m_nThread, logEntry.m_ach ); } else if (nVerbose == 1) { dprintf( "\n%6d: Thread = %04x, TimeStamp = %04x %04x %04x %04x\n" "%s\n", index, logEntry.m_nThread, HIWORD(logEntry.m_liTimeStamp.HighPart), LOWORD(logEntry.m_liTimeStamp.HighPart), HIWORD(logEntry.m_liTimeStamp.LowPart), LOWORD(logEntry.m_liTimeStamp.LowPart), logEntry.m_ach ); } } } // DumpStringTraceLog DECLARE_API( st ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a print trace log. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). 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 asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { INIT_API(); DumpStringTraceLog( lpArgumentString, FALSE ); } // DECLARE_API( st ) DECLARE_API( rst ) /*++ Routine Description: This function is called as an NTSD extension to format and dump a print trace log backwards. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). 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 asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { INIT_API(); DumpStringTraceLog( lpArgumentString, TRUE ); } // DECLARE_API( rst ) DECLARE_API( resetst ) /*++ Routine Description: This function is called as an NTSD extension to reset a print trace log back to its initial state. Arguments: hCurrentProcess - Supplies a handle to the current process (at the time the extension was called). hCurrentThread - Supplies a handle to the current thread (at the time the extension was called). 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 asciiz string that describes the ansi string to be dumped. Return Value: None. --*/ { ULONG_PTR stlLogAddress = 0; CStringTraceLog stlHeader; TRACE_LOG tlogHeader; CStringTraceLog::CLogEntry logEntry; INIT_API(); // // Skip leading blanks. // while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; } if( *lpArgumentString == '\0' ) { PrintUsage( "resetst" ); return; } stlLogAddress = GetExpression( lpArgumentString ); if( stlLogAddress == 0 ) { dprintf( "inetdbg.resetst: cannot evaluate \"%s\"\n", lpArgumentString ); return; } // // Read the log header, perform some sanity checks. // if( !ReadMemory( stlLogAddress, &stlHeader, sizeof(stlHeader), NULL ) ) { dprintf( "inetdbg.resetst: cannot read memory @ %p\n", stlLogAddress ); return; } if( !ReadMemory( stlHeader.m_ptlog, &tlogHeader, sizeof(tlogHeader), NULL ) ) { dprintf( "inetdbg.resetst: cannot read tracelog memory @ %p\n", (PVOID)stlHeader.m_ptlog ); return; } dprintf( "inetdbg.resetst: log @ %p:\n" " String Trace Log Signature = %08lx (%s)\n" " Trace Log Signature = %08lx (%s)\n" " LogSize = %lu\n" " NextEntry = %lu\n" " EntrySize = %lu\n" " LogBuffer = %08lp\n", (PVOID) stlLogAddress, stlHeader.m_Signature, stlHeader.m_Signature == CStringTraceLog::SIGNATURE ? "OK" : stlHeader.m_Signature == CStringTraceLog::SIGNATURE_X ? "FREED" : "INVALID", tlogHeader.Signature, tlogHeader.Signature == TRACE_LOG_SIGNATURE ? "OK" : tlogHeader.Signature == TRACE_LOG_SIGNATURE_X ? "FREED" : "INVALID", tlogHeader.LogSize, tlogHeader.NextEntry, tlogHeader.EntrySize, tlogHeader.LogBuffer ); if( tlogHeader.LogBuffer > ( (PUCHAR)stlHeader.m_ptlog + sizeof(tlogHeader) ) ) { dprintf( " Extra Data @ %p\n", (PVOID)( stlLogAddress + sizeof(tlogHeader) ) ); } if( stlHeader.m_Signature != CStringTraceLog::SIGNATURE && stlHeader.m_Signature != CStringTraceLog::SIGNATURE_X ) { dprintf( "inetdbg.resetst: log @ %p has invalid signature %08lx:\n", (PVOID) stlLogAddress, stlHeader.m_Signature ); return; } if( (UINT) tlogHeader.EntrySize != sizeof(CStringTraceLog::CLogEntry) - CStringTraceLog::MAX_CCH + stlHeader.m_cch ) { dprintf( "inetdbg.resetst: log @ %p is not a print trace log\n", (PVOID) stlLogAddress ); return; } // // Reset it. // tlogHeader.NextEntry = -1; if( !WriteMemory( stlHeader.m_ptlog, &tlogHeader, sizeof(tlogHeader), NULL ) ) { dprintf( "inetdbg.resetst: cannot write memory @ %p\n", (PVOID) stlHeader.m_ptlog ); return; } dprintf( "inetdbg.resetst: log @ %p reset\n", (PVOID) stlHeader.m_ptlog ); } // DECLARE_API( resetst )