/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: tracelog.c Abstract: Sample trace control program. Allows user to start, update, query, stop event tracing, etc. --*/ #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #include #include #include #include #include #include #include #include #include #define MAXSTR 1024 #define DEFAULT_LOGFILE_NAME _T("C:\\LogFile.Etl") #define NT_LOGGER _T("NT Kernel Logger") #define MAXIMUM_LOGGERS 32 #define MAXGUIDS 128 #define ACTION_QUERY 0 #define ACTION_START 1 #define ACTION_STOP 2 #define ACTION_UPDATE 3 #define ACTION_LIST 4 #define ACTION_ENABLE 5 #define ACTION_HELP 6 #define ACTION_FLUSH 7 #define ACTION_ENUM_GUID 8 #define ACTION_UNDEFINED 10 #define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID))) // // Functions not implemented on Win2K need to be searched and loaded separately. // To make further accesses easy, an array of function pointers will be used. // The following list serves as indices to that array. // #define FUNC_FLUSH_TRACE 0 #define FUNC_ENUM_TRACE_GUIDS 1 // Funtion pointer array for unimplemented functions on Win2K. // Note: This may not work if this code is ported to C++, because // all the function pointers may be typedefed differently. #define MAXFUNC 10 FARPROC FuncArray[MAXFUNC]; HINSTANCE advapidll; BOOLEAN XP; void PrintLoggerStatus( IN PEVENT_TRACE_PROPERTIES LoggerInfo, IN ULONG Status, IN BOOL PrintStatus ); #define PRINTSTATUS TRUE #define NOPRINTSTATUS FALSE LPTSTR DecodeStatus( IN ULONG Status ); LONG GetGuids( IN LPTSTR GuidFile, OUT LPGUID *GuidArray ); ULONG ahextoi( IN TCHAR *s ); void StringToGuid( IN TCHAR *str, OUT LPGUID guid ); PTCHAR GuidToString( IN OUT PTCHAR s, IN LPGUID piid ); TCHAR ErrorMsg[MAXSTR]; void PrintHelpMessage(); // // main function // __cdecl main(argc, argv) int argc; char **argv; /*++ Routine Description: It is the main function. Arguments: Return Value: Error Code defined in winerror.h : If the function succeeds, it returns ERROR_SUCCESS (== 0). --*/{ ULONG i, j; LONG GuidCount; USHORT Action = ACTION_UNDEFINED; ULONG Status = 0; LPTSTR LoggerName; LPTSTR LogFileName; TCHAR GuidFile[MAXSTR]; PEVENT_TRACE_PROPERTIES pLoggerInfo; TRACEHANDLE LoggerHandle = 0; LPTSTR *targv, *utargv = NULL; LPGUID *GuidArray; char *Space; char *save; BOOL bKill = FALSE; BOOL bForceKill = FALSE ; BOOL bEnable = TRUE; ULONG iLevel = 0; ULONG iFlags = 0; ULONG SizeNeeded = 0; ULONG specialLogger = 0; ULONG GlobalLoggerStartValue = 0; PULONG pFlags = NULL; BOOL bProcess = TRUE; BOOL bThread = TRUE; BOOL bDisk = TRUE; BOOL bNetwork = TRUE; TCHAR tstrLogFileName[MAXSTR]; OSVERSIONINFO OSVersion; OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); XP = FALSE; if (GetVersionEx(&OSVersion)) { XP = (OSVersion.dwMajorVersion > 5) || ((OSVersion.dwMajorVersion == 5) && (OSVersion.dwMinorVersion > 0)); } // Load functions that are not implemented on Win2K for (i = 0; i < MAXFUNC; ++i) FuncArray[i] = NULL; if (XP) { advapidll = LoadLibrary(_T("advapi32.dll")); if (advapidll != NULL) { #ifdef UNICODE FuncArray[FUNC_FLUSH_TRACE] = GetProcAddress(advapidll, "FlushTraceW"); #else FuncArray[FUNC_FLUSH_TRACE] = GetProcAddress(advapidll, "FlushTraceA"); #endif FuncArray[FUNC_ENUM_TRACE_GUIDS] = GetProcAddress(advapidll, "EnumerateTraceGuids"); } } // Initialize structure first SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR); pLoggerInfo = (PEVENT_TRACE_PROPERTIES) malloc(SizeNeeded); if (pLoggerInfo == NULL) { if (advapidll != NULL) FreeLibrary(advapidll); return (ERROR_OUTOFMEMORY); } RtlZeroMemory(pLoggerInfo, SizeNeeded); pLoggerInfo->Wnode.BufferSize = SizeNeeded; pLoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID; pLoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pLoggerInfo->LogFileNameOffset = pLoggerInfo->LoggerNameOffset + MAXSTR * sizeof(TCHAR); LoggerName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LoggerNameOffset); LogFileName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LogFileNameOffset); _tcscpy(LoggerName, NT_LOGGER); Space = (char*) malloc( (MAXGUIDS * sizeof(GuidArray)) + (MAXGUIDS * sizeof(GUID) )); if (Space == NULL) { free(pLoggerInfo); if (advapidll != NULL) FreeLibrary(advapidll); return(ERROR_OUTOFMEMORY); } save = Space; GuidArray = (LPGUID *) Space; Space += MAXGUIDS * sizeof(GuidArray); for (GuidCount=0; GuidCountEnableFlags; // // Add default flags. // while (--argc > 0) { ++targv; if (**targv == '-' || **targv == '/') { // argument found if(targv[0][0] == '/' ) targv[0][0] = '-'; if (!_tcsicmp(targv[0], _T("-start"))) { Action = ACTION_START; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-enable"))) { Action = ACTION_ENABLE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-disable"))) { Action = ACTION_ENABLE; bEnable = FALSE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-stop"))) { Action = ACTION_STOP; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-update"))) { Action = ACTION_UPDATE; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-q"))) { Action = ACTION_QUERY; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-flush"))) { Action = ACTION_FLUSH; if (argc > 1) { if (targv[1][0] != '-' && targv[1][0] != '/') { ++targv; --argc; _tcscpy(LoggerName, targv[0]); } } } else if (!_tcsicmp(targv[0], _T("-enumguid"))) { Action = ACTION_ENUM_GUID; } else if (!_tcsicmp(targv[0], _T("-f"))) { if (argc > 1) { _tcscpy(LogFileName, targv[1]); _tcscpy(tstrLogFileName, targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-append"))) { if (argc > 1) { _tfullpath(LogFileName, targv[1], MAXSTR); _tcscpy(tstrLogFileName, LogFileName); ++targv; --argc; pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_APPEND; } } else if (!_tcsicmp(targv[0], _T("-guid"))) { if (argc > 1) { if (targv[1][0] == _T('#')) { StringToGuid(&targv[1][1], GuidArray[0]); ++targv; --argc; GuidCount = 1; } else if (targv[1][0] != '-' && targv[1][0] != '/') { _tfullpath(GuidFile, targv[1], MAXSTR); ++targv; --argc; GuidCount = GetGuids(GuidFile, GuidArray); if (GuidCount < 0) { _tprintf( _T("Error: %s does no exist\n"), GuidFile ); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } else if (GuidCount == 0){ _tprintf( _T("Error: %s is invalid\n"), GuidFile ); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } } } } else if (!_tcsicmp(targv[0], _T("-seq"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_SEQUENTIAL; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-newfile"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_NEWFILE; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-cir"))) { if (argc > 1) { pLoggerInfo->LogFileMode |= EVENT_TRACE_FILE_MODE_CIRCULAR; pLoggerInfo->MaximumFileSize = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-b"))) { if (argc > 1) { pLoggerInfo->BufferSize = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-flag")) || !_tcsicmp(targv[0], _T("-flags"))) { if (argc > 1) { if (targv[1][1] == _T('x') || targv[1][1] == _T('X')) { pLoggerInfo->EnableFlags |= ahextoi(targv[1]); } else { pLoggerInfo->EnableFlags |= _ttoi(targv[1]); } iFlags = pLoggerInfo->EnableFlags ; // Copy for EnableTrace ++targv; --argc; // Do not accept flags with MSB = 1. if (0x80000000 & pLoggerInfo->EnableFlags) { _tprintf(_T("Invalid Flags: 0x%0X(%d.)\n"), pLoggerInfo->EnableFlags, pLoggerInfo->EnableFlags); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } } } else if (!_tcsicmp(targv[0], _T("-min"))) { if (argc > 1) { pLoggerInfo->MinimumBuffers = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-max"))) { if (argc > 1) { pLoggerInfo->MaximumBuffers = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-level"))) { if (argc > 1) { iLevel = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-ft"))) { if (argc > 1) { pLoggerInfo->FlushTimer = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-um"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE; } else if (!_tcsicmp(targv[0], _T("-paged"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY; } else if (!_tcsicmp(targv[0], _T("-rt"))) { pLoggerInfo->LogFileMode |= EVENT_TRACE_REAL_TIME_MODE; } else if (!_tcsicmp(targv[0], _T("-age"))) { if (argc > 1) { pLoggerInfo->AgeLimit = _ttoi(targv[1]); ++targv; --argc; } } else if (!_tcsicmp(targv[0], _T("-l"))) { Action = ACTION_LIST; bKill = FALSE; } else if (!_tcsicmp(targv[0], _T("-x"))) { Action = ACTION_LIST; bKill = TRUE; } else if (!_tcsicmp(targv[0], _T("-xf"))) { Action = ACTION_LIST; bKill = TRUE; bForceKill = TRUE ; } else if (!_tcsicmp(targv[0], _T("-noprocess"))) { bProcess = FALSE; } else if (!_tcsicmp(targv[0], _T("-nothread"))) { bThread = FALSE; } else if (!_tcsicmp(targv[0], _T("-nodisk"))) { bDisk = FALSE; } else if (!_tcsicmp(targv[0], _T("-nonet"))) { bNetwork = FALSE; } else if (!_tcsicmp(targv[0], _T("-fio"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_DISK_FILE_IO; } else { _tprintf(_T("Option -fio cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-pf"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS; } else { _tprintf(_T("Option -pf cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-hf"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS; } else { _tprintf(_T("Option -hf cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-img"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD; } else { _tprintf(_T("Option -img cannot be used with -eflags. Ignored\n")); } } else if (!_tcsicmp(targv[0], _T("-cm"))) { if (pFlags == &pLoggerInfo->EnableFlags) { *pFlags |= EVENT_TRACE_FLAG_REGISTRY; } else { _tprintf(_T("Option -cm cannot be used with -eflags. Ignored\n")); } } else if ( targv[0][1] == 'h' || targv[0][1] == 'H' || targv[0][1] == '?'){ Action = ACTION_HELP; PrintHelpMessage(); goto CleanupExit; } else Action = ACTION_UNDEFINED; } else { _tprintf(_T("Invalid option given: %s\n"), targv[0]); Status = ERROR_INVALID_PARAMETER; goto CleanupExit; } } if (!_tcscmp(LoggerName, NT_LOGGER)) { if (pFlags == &pLoggerInfo->EnableFlags) { if (bProcess) *pFlags |= EVENT_TRACE_FLAG_PROCESS; if (bThread) *pFlags |= EVENT_TRACE_FLAG_THREAD; if (bDisk) *pFlags |= EVENT_TRACE_FLAG_DISK_IO; if (bNetwork) *pFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP; } pLoggerInfo->Wnode.Guid = SystemTraceControlGuid; // defaults to OS specialLogger = 1; } if ( !(pLoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) ) { if (specialLogger != 3 && _tcslen(LogFileName) <= 0 && Action == ACTION_START) { _tcscpy(LogFileName, DEFAULT_LOGFILE_NAME); // for now... _tcscpy(tstrLogFileName, DEFAULT_LOGFILE_NAME); } } switch (Action) { case ACTION_START: { if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } Status = StartTrace(&LoggerHandle, LoggerName, pLoggerInfo); if (Status != ERROR_SUCCESS) { _tprintf(_T("Could not start logger: %s\n") _T("Operation Status: %uL\n") _T("%s\n"), LoggerName, Status, DecodeStatus(Status)); break; } _tprintf(_T("Logger Started...\n")); case ACTION_ENABLE: if (Action == ACTION_ENABLE ){ if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } Status = ControlTrace((TRACEHANDLE) 0, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if( Status != ERROR_SUCCESS ){ _tprintf( _T("ERROR: Logger not started\n") _T("Operation Status: %uL\n") _T("%s\n"), Status, DecodeStatus(Status)); break; } LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; } if ( (GuidCount > 0) && (specialLogger == 0)) { _tprintf(_T("Enabling trace to logger %d\n"), LoggerHandle); for (i = 0; i < (ULONG)GuidCount; i++) { Status = EnableTrace ( bEnable, iFlags, iLevel, GuidArray[i], LoggerHandle); // // If some of the Guids can not be enabled, consider it a benign // failure. Print a warning message and continue. // if (Status == ERROR_INVALID_OPERATION) { _tprintf(_T("WARNING: Could not enable some guids.\n")); _tprintf(_T("Check your Guids file\n")); Status = ERROR_SUCCESS; } if (Status != ERROR_SUCCESS) { _tprintf(_T("ERROR: Failed to enable Guid [%d]...\n"), i); _tprintf(_T("Operation Status: %uL\n"), Status); _tprintf(_T("%s\n"),DecodeStatus(Status)); break; } } } else { if (GuidCount > 0) { _tprintf(_T("ERROR: System Logger does not accept application guids...\n")); Status = ERROR_INVALID_PARAMETER; } } break; } case ACTION_STOP : LoggerHandle = (TRACEHANDLE) 0; Status = ERROR_SUCCESS; if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } if (specialLogger != 0) { if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if (Status != ERROR_SUCCESS) break; LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; Status = EnableTrace( FALSE, EVENT_TRACE_PRIVATE_LOGGER_MODE, 0, GuidArray[0], LoggerHandle ); } else { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); if (Status == ERROR_WMI_INSTANCE_NOT_FOUND) break; LoggerHandle = pLoggerInfo->Wnode.HistoricalContext; for (i = 0; i < (ULONG)GuidCount; i++) { Status = EnableTrace( FALSE, 0, 0, GuidArray[i], LoggerHandle); } } } Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_STOP); break; case ACTION_LIST : { ULONG i, returnCount ; ULONG SizeNeeded; PEVENT_TRACE_PROPERTIES pLoggerInfo[MAXIMUM_LOGGERS]; PEVENT_TRACE_PROPERTIES pStorage; PVOID Storage; SizeNeeded = MAXIMUM_LOGGERS * (sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR)); Storage = malloc(SizeNeeded); if (Storage == NULL) { Status = ERROR_OUTOFMEMORY; break; } RtlZeroMemory(Storage, SizeNeeded); pStorage = (PEVENT_TRACE_PROPERTIES)Storage; for (i=0; iWnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR); pStorage->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + MAXSTR * sizeof(TCHAR); pStorage->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pLoggerInfo[i] = pStorage; pStorage = (PEVENT_TRACE_PROPERTIES) ( (char*)pStorage + pStorage->Wnode.BufferSize); } Status = QueryAllTraces(pLoggerInfo, MAXIMUM_LOGGERS, & returnCount); if (Status == ERROR_SUCCESS) { for (j= 0; j < returnCount; j++) { LPTSTR LoggerName; TCHAR asked = _T('?') ; BOOL StatusPrint = FALSE ; if (bKill) { LoggerName = (LPTSTR) ((char*)pLoggerInfo[j] + pLoggerInfo[j]->LoggerNameOffset); if (!bForceKill) { while (!(asked == _T('y')) && !(asked == _T('n'))) { _tprintf(_T("Do you want to kill Logger \"%s\" (Y or N)?"),LoggerName); _tscanf(_T(" %c"),&asked); if (asked == _T('Y')) { asked = _T('y') ; } else if (asked == _T('N')) { asked = _T('n') ; } } } else { asked = _T('y'); } if (asked == _T('y')) { if (!IsEqualGUID(& pLoggerInfo[j]->Wnode.Guid, & SystemTraceControlGuid)) { LoggerHandle = pLoggerInfo[j]->Wnode.HistoricalContext; Status = EnableTrace( FALSE, (pLoggerInfo[j]->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) ? (EVENT_TRACE_PRIVATE_LOGGER_MODE) : (0), 0, & pLoggerInfo[j]->Wnode.Guid, LoggerHandle); } Status = ControlTrace((TRACEHANDLE) 0, LoggerName, pLoggerInfo[j], EVENT_TRACE_CONTROL_STOP); _tprintf(_T("Logger \"%s\" has been killed\n"),LoggerName); StatusPrint = TRUE ; } else { _tprintf(_T("Logger \"%s\" has not been killed, current Status is\n"),LoggerName); StatusPrint = FALSE ; } } PrintLoggerStatus(pLoggerInfo[j], Status, StatusPrint); _tprintf(_T("\n")); } } i = 0; free(Storage); break; } case ACTION_UPDATE : case ACTION_FLUSH : case ACTION_QUERY : if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) { if (GuidCount != 1) { _tprintf(_T("Need exactly one GUID for PRIVATE loggers\n")); Status = ERROR_INVALID_PARAMETER; break; } pLoggerInfo->Wnode.Guid = *GuidArray[0]; } if (Action == ACTION_QUERY) { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY); } else if (Action == ACTION_UPDATE) { Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_UPDATE); } else if (Action == ACTION_FLUSH) { // Since FlushTrace is not implemented on Win2K, use the function pointer // loaded from advapi32.dll separately. // Originally, this block had one line: // Status = FlushTrace(LoggerHandle, LoggerName, pLoggerInfo); if (FuncArray[FUNC_FLUSH_TRACE] == NULL) { _tprintf(_T("Flush Trace is not supported on this system\n")); Status = ERROR_INVALID_PARAMETER; break; } Status = (ULONG)(*FuncArray[FUNC_FLUSH_TRACE])(LoggerHandle, LoggerName, pLoggerInfo); } break; case ACTION_ENUM_GUID: { ULONG i; ULONG PropertyArrayCount=10; PTRACE_GUID_PROPERTIES *GuidPropertiesArray; ULONG GuidCount; ULONG SizeStorage; PVOID StorageNeeded; PTRACE_GUID_PROPERTIES CleanStorage; TCHAR str[MAXSTR]; // Since EnumTraceGuids is not implemented on Win2K, use the function pointer // loaded from advapi32.dll separately. if (FuncArray[FUNC_ENUM_TRACE_GUIDS] == NULL) { _tprintf(_T("Enumerating trace GUIDS is not supported on this system\n")); Status = ERROR_INVALID_PARAMETER; break; } Retry: SizeStorage = PropertyArrayCount * (sizeof(TRACE_GUID_PROPERTIES) + sizeof(PTRACE_GUID_PROPERTIES)); StorageNeeded = malloc(SizeStorage); if (StorageNeeded== NULL) { Status = ERROR_OUTOFMEMORY; break; } RtlZeroMemory(StorageNeeded, SizeStorage); GuidPropertiesArray = (PTRACE_GUID_PROPERTIES *)StorageNeeded; CleanStorage = (PTRACE_GUID_PROPERTIES)((char*)StorageNeeded + PropertyArrayCount * sizeof(PTRACE_GUID_PROPERTIES)); for (i=0; i < PropertyArrayCount; i++) { GuidPropertiesArray[i] = CleanStorage; CleanStorage = (PTRACE_GUID_PROPERTIES) ( (char*)CleanStorage + sizeof(TRACE_GUID_PROPERTIES) ); } // Use function pointer for EnumTraceGuids Status = (ULONG)(*FuncArray[FUNC_ENUM_TRACE_GUIDS])(GuidPropertiesArray,PropertyArrayCount,&GuidCount); if(Status == ERROR_MORE_DATA) { PropertyArrayCount=GuidCount; free(StorageNeeded); goto Retry; } // // print the GUID_PROPERTIES and Free Strorage // _tprintf(_T(" Guid Enabled LoggerId Level Flags\n")); _tprintf(_T("------------------------------------------------------------\n")); for (i=0; i < GuidCount; i++) { _tprintf(_T("%s %5s %d %d %d\n"), GuidToString(&str[0],&GuidPropertiesArray[i]->Guid), (GuidPropertiesArray[i]->IsEnable) ? _T("TRUE") : _T("FALSE"), GuidPropertiesArray[i]->LoggerId, GuidPropertiesArray[i]->EnableLevel, GuidPropertiesArray[i]->EnableFlags ); } free(StorageNeeded); } break; case ACTION_HELP: PrintHelpMessage(); break; default : _tprintf(_T("Error: no action specified\n")); PrintHelpMessage(); break; } if ((Action != ACTION_HELP) && (Action != ACTION_ENUM_GUID) && (Action != ACTION_UNDEFINED) && (Action != ACTION_LIST)) PrintLoggerStatus(pLoggerInfo, Status, PRINTSTATUS); CleanupExit: SetLastError(Status); if (utargv != NULL) { GlobalFree(utargv); } free(pLoggerInfo); free(save); if (advapidll != NULL) FreeLibrary(advapidll); return(Status); } void PrintLoggerStatus( IN PEVENT_TRACE_PROPERTIES LoggerInfo, IN ULONG Status, IN BOOL PrintStatus ) /*++ Routine Description: Prints out the status of the specified logger. Arguments: LoggerInfo - The pointer to the resident EVENT_TRACE_PROPERTIES that has the information about the current logger. Status - The returned status of the last executed command or the operation status of the current logger. PrintStatus - Determines which type of status it is using. Return Value: None --*/ { LPTSTR LoggerName, LogFileName; if ((LoggerInfo->LoggerNameOffset > 0) && (LoggerInfo->LoggerNameOffset < LoggerInfo->Wnode.BufferSize)) { LoggerName = (LPTSTR) ((char*)LoggerInfo + LoggerInfo->LoggerNameOffset); } else LoggerName = NULL; if ((LoggerInfo->LogFileNameOffset > 0) && (LoggerInfo->LogFileNameOffset < LoggerInfo->Wnode.BufferSize)) { LogFileName = (LPTSTR) ((char*)LoggerInfo + LoggerInfo->LogFileNameOffset); } else LogFileName = NULL; if (PrintStatus) { _tprintf(_T("Operation Status: %uL\t"), Status); _tprintf(_T("%s\n"), DecodeStatus(Status)); } _tprintf(_T("Logger Name: %s\n"), (LoggerName == NULL) ? _T(" ") : LoggerName); _tprintf(_T("Logger Id: %I64x\n"), LoggerInfo->Wnode.HistoricalContext); _tprintf(_T("Logger Thread Id: %d\n"), LoggerInfo->LoggerThreadId); if (Status != 0) return; _tprintf(_T("Buffer Size: %d Kb"), LoggerInfo->BufferSize); if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_PAGED_MEMORY) { _tprintf(_T(" using paged memory\n")); } else { _tprintf(_T("\n")); } _tprintf(_T("Maximum Buffers: %d\n"), LoggerInfo->MaximumBuffers); _tprintf(_T("Minimum Buffers: %d\n"), LoggerInfo->MinimumBuffers); _tprintf(_T("Number of Buffers: %d\n"), LoggerInfo->NumberOfBuffers); _tprintf(_T("Free Buffers: %d\n"), LoggerInfo->FreeBuffers); _tprintf(_T("Buffers Written: %d\n"), LoggerInfo->BuffersWritten); _tprintf(_T("Events Lost: %d\n"), LoggerInfo->EventsLost); _tprintf(_T("Log Buffers Lost: %d\n"), LoggerInfo->LogBuffersLost); _tprintf(_T("Real Time Buffers Lost: %d\n"), LoggerInfo->RealTimeBuffersLost); _tprintf(_T("AgeLimit: %d\n"), LoggerInfo->AgeLimit); if (LogFileName == NULL) { _tprintf(_T("Buffering Mode: ")); } else { _tprintf(_T("Log File Mode: ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) { _tprintf(_T("Append ")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) { _tprintf(_T("Circular\n")); } else if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) { _tprintf(_T("Sequential\n")); } else { _tprintf(_T("Sequential\n")); } if (LoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) { _tprintf(_T("Real Time mode enabled")); _tprintf(_T("\n")); } if (LoggerInfo->MaximumFileSize > 0) _tprintf(_T("Maximum File Size: %d Mb\n"), LoggerInfo->MaximumFileSize); if (LoggerInfo->FlushTimer > 0) _tprintf(_T("Buffer Flush Timer: %d secs\n"), LoggerInfo->FlushTimer); if (LoggerInfo->EnableFlags != 0) { _tprintf(_T("Enabled tracing: ")); if ((LoggerName != NULL) && (!_tcscmp(LoggerName,NT_LOGGER))) { if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_PROCESS) _tprintf(_T("Process ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_THREAD) _tprintf(_T("Thread ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_IO) _tprintf(_T("Disk ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) _tprintf(_T("File ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) _tprintf(_T("PageFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS) _tprintf(_T("HardFaults ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) _tprintf(_T("ImageLoad ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP) _tprintf(_T("TcpIp ")); if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_REGISTRY) _tprintf(_T("Registry ")); }else{ _tprintf(_T("0x%08x"), LoggerInfo->EnableFlags ); } _tprintf(_T("\n")); } if (LogFileName != NULL) { _tprintf(_T("Log Filename: %s\n"), LogFileName); } } LPTSTR DecodeStatus( IN ULONG Status ) /*++ Routine Description: Decodes WIN32 error into a string in the default language. Arguments: Status - The error status from the last executed command or the operation status of the current logger. Return Value: LPTSTR - String containing the decoded message. --*/ { memset( ErrorMsg, 0, MAXSTR ); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, Status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) ErrorMsg, MAXSTR, NULL ); return ErrorMsg; } LONG GetGuids( IN LPTSTR GuidFile, IN OUT LPGUID *GuidArray ) /*++ Routine Description: Reads GUIDs from a file and stores them in an GUID array. Arguments: GuidFile - The file containing GUIDs. GuidArray - The GUID array that will have GUIDs read from the file. Return Value: ULONG - The number of GUIDs processed. --*/ { FILE *f; TCHAR line[MAXSTR], arg[MAXSTR]; LPGUID Guid; int i, n; f = _tfopen((TCHAR*)GuidFile, _T("r")); if (f == NULL) return -1; n = 0; while ( _fgetts(line, MAXSTR, f) != NULL ) { if (_tcslen(line) < 36) continue; if (line[0] == ';' || line[0] == '\0' || line[0] == '#' || line[0] == '/') continue; Guid = (LPGUID) GuidArray[n]; n ++; _tcsncpy(arg, line, 8); arg[8] = 0; Guid->Data1 = ahextoi(arg); _tcsncpy(arg, &line[9], 4); arg[4] = 0; Guid->Data2 = (USHORT) ahextoi(arg); _tcsncpy(arg, &line[14], 4); arg[4] = 0; Guid->Data3 = (USHORT) ahextoi(arg); for (i=0; i<2; i++) { _tcsncpy(arg, &line[19 + (i*2)], 2); arg[2] = 0; Guid->Data4[i] = (UCHAR) ahextoi(arg); } for (i=2; i<8; i++) { _tcsncpy(arg, &line[20 + (i*2)], 2); arg[2] = 0; Guid->Data4[i] = (UCHAR) ahextoi(arg); } } return (ULONG)n; } ULONG ahextoi( IN TCHAR *s ) /*++ Routine Description: Converts a hex string into a number. Arguments: s - A hex string in TCHAR. Return Value: ULONG - The number in the string. --*/ { int len; ULONG num, base, hex; len = _tcslen(s); hex = 0; base = 1; num = 0; while (--len >= 0) { if ( (s[len] == 'x' || s[len] == 'X') && (s[len-1] == '0') ) break; if (s[len] >= '0' && s[len] <= '9') num = s[len] - '0'; else if (s[len] >= 'a' && s[len] <= 'f') num = (s[len] - 'a') + 10; else if (s[len] >= 'A' && s[len] <= 'F') num = (s[len] - 'A') + 10; else continue; hex += num * base; base = base * 16; } return hex; } void StringToGuid( IN TCHAR *str, IN OUT LPGUID guid ) /*++ Routine Description: Converts a string into a GUID. Arguments: str - A string in TCHAR. guid - The pointer to a GUID that will have the converted GUID. Return Value: None. --*/ { TCHAR temp[10]; int i, n; temp[8]=_T('\0'); _tcsncpy(temp, str, 8); _stscanf(temp, _T("%x"), &(guid->Data1)); temp[4]=_T('\0'); _tcsncpy(temp, &str[9], 4); _stscanf(temp, _T("%x"), &(guid->Data2)); _tcsncpy(temp, &str[14], 4); _stscanf(temp, _T("%x"), &(guid->Data3)); temp[2]='\0'; for(i=0;i<8;i++) { temp[0]=str[19+((i<2)?2*i:2*i+1)]; // to accomodate the minus sign after temp[1]=str[20+((i<2)?2*i:2*i+1)]; // the first two chars _stscanf(temp, _T("%x"), &n); // if used more than byte alloc guid->Data4[i]=(unsigned char)n; // causes overrun of memory } } void PrintHelpMessage() /*++ Routine Description: prints out a help message. Arguments: None. Return Value: None. --*/ { _tprintf(_T("Usage: tracelog [actions] [options] | [-h | -help | -?]\n")); _tprintf(_T("\n actions:\n")); _tprintf(_T("\t-start [LoggerName] Starts up the [LoggerName] trace session\n")); _tprintf(_T("\t-stop [LoggerName] Stops the [LoggerName] trace session\n")); _tprintf(_T("\t-update [LoggerName] Updates the [LoggerName] trace session\n")); _tprintf(_T("\t-enable [LoggerName] Enables providers for the [LoggerName] session\n")); _tprintf(_T("\t-disable [LoggerName] Disables providers for the [LoggerName] session\n")); if (XP) { _tprintf(_T("\t-flush [LoggerName] Flushes the [LoggerName] active buffers\n")); _tprintf(_T("\t-enumguid Enumerate Registered Trace Guids\n")); } _tprintf(_T("\t-q [LoggerName] Query status of [LoggerName] trace session\n")); _tprintf(_T("\t-l List all trace sessions\n")); _tprintf(_T("\t-x Stops all active trace sessions\n")); _tprintf(_T("\n options:\n")); _tprintf(_T("\t-b Sets buffer size to Kbytes\n")); _tprintf(_T("\t-min Sets minimum buffers\n")); _tprintf(_T("\t-max Sets maximum buffers\n")); _tprintf(_T("\t-f Log to file \n")); if (XP) { _tprintf(_T("\t-append Append to file \n")); } _tprintf(_T("\t-seq Sequential logfile of up to n Mbytes\n")); _tprintf(_T("\t-cir Circular logfile of n Mbytes\n")); if (XP) { _tprintf(_T("\t-newfile Log to a new file after every n Mbytes\n")); } _tprintf(_T("\t-ft Set flush timer to n seconds\n")); if (XP) { _tprintf(_T("\t-paged Use pageable memory for buffers\n")); } _tprintf(_T("\t-noprocess Disable Process Start/End tracing\n")); _tprintf(_T("\t-nothread Disable Thread Start/End tracing\n")); _tprintf(_T("\t-nodisk Disable Disk I/O tracing\n")); _tprintf(_T("\t-nonet Disable Network TCP/IP tracing\n")); _tprintf(_T("\t-fio Enable file I/O tracing\n")); _tprintf(_T("\t-pf Enable page faults tracing\n")); _tprintf(_T("\t-hf Enable hard faults tracing\n")); _tprintf(_T("\t-img Enable image load tracing\n")); _tprintf(_T("\t-cm Enable registry calls tracing\n")); _tprintf(_T("\t-um Enable Process Private tracing\n")); _tprintf(_T("\t-guid Start tracing for providers in file\n")); _tprintf(_T("\t-rt Enable tracing in real time mode\n")); _tprintf(_T("\t-age Modify aging decay time to n minutes\n")); _tprintf(_T("\t-level Enable Level passed to the providers\n")); _tprintf(_T("\t-flag Enable Flags passed to the providers\n")); _tprintf(_T("\n")); _tprintf(_T("\t-h\n")); _tprintf(_T("\t-help\n")); _tprintf(_T("\t-? Display usage information\n")); } PTCHAR GuidToString( IN OUT PTCHAR s, LPGUID piid ) /*++ Routine Description: Converts a GUID into a string. Arguments: s - A string in TCHAR that will have the converted GUID. piid - The pointer to a GUID. Return Value: PTCHAR - The string containig the convereted GUID. --*/ { _stprintf(s, _T("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"), piid->Data1, piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2], piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]); return(s); }