/*++ Copyright (c) 1999-2000 Microsoft Corporation Module Name : trc.cpp Abstract: Kernel-Mode Tracing Facility. This module utilizes DCL's tracing macros, defined in atrcapi.h, in a way that is intended to be independent of anything but NT DDK API's. Currently, rdpwd.sys and rdpdd.sys also use these shared macros, but not in a way that is independent of their respective components. Author: Revision History: --*/ #include "precomp.hxx" #include #define TRC_FILE "trc" #include "trc.h" // // This module shouldn't do much if we are not in a checked build. // #if DBG //////////////////////////////////////////////////////////////////////// // // Globals to this Module // // // Current Tracing Parameters // TRC_CONFIG TRC_Config = TRC_CONFIG_DEFAULT; // // InterlockedIncrement is a preincrement, first thing will roll over // and fill in entry 0 // ULONG TRC_CurrentMsg = 0xFFFFFFFF; // // Recent Traces // CHAR TRC_RecentTraces[TRC_RamMsgMax][TRC_BUFFER_SIZE]; BOOL TRC_ProfileTraceEnabled() { return TRC_Config.TraceProfile; } VOID TRC_TraceLine( ULONG traceLevel, PCHAR traceString, CHAR separator, ULONG lineNumber, PCHAR funcName, PCHAR fileName ) /*++ Routine Description: "C" Tracing Entry Point. From the perspective of the tracing macros, this function actaully does the tracing. Arguments: traceClass - Component doing the tracing traceType - ERR, ALT, NRM, DBG traceString - Unadorned message separator - separator character lineNumber - lineNumber where the TRC_XXX call was made funcName - function containing the TRC_XXX call fileName - file containing the TRC_XXX call Return Value: NA --*/ { CHAR *msgBufEntry; ULONG ofs; CHAR tempString[TRC_BUFFER_SIZE]=""; CHAR formatString[TRC_BUFFER_SIZE]=""; ULONG_PTR processId; ULONG_PTR threadId; LARGE_INTEGER time; TIME_FIELDS TimeFields; ULONG idxBuffer; // // CODE_IMPROVMENT: Currently creates a big tracing string. Might be cool // save tracing records with all the fields so that the debugger ext. // could choose the output formatting on the fly. i.e. print just the // level you want, no grep required // // // Grab the next element in the RAM message buffer. We use the // mask to define which bits we are using for the counter. This // allows us to wrap the counter in one call to InterlockedIncrement. // idxBuffer = InterlockedIncrement((PLONG)&TRC_CurrentMsg) & TRC_RamMsgMask; msgBufEntry = (char *)&TRC_RecentTraces[idxBuffer]; msgBufEntry[0] = 0; processId = (ULONG_PTR)PsGetCurrentProcess(); //threadId = (ULONG_PTR)PsGetCurrentThread(); threadId = 0; KeQuerySystemTime(&time); RtlTimeToTimeFields(&time, &TimeFields); // // Add the timestamp. // _snprintf(tempString, sizeof(tempString), TRC_TIME_FMT "%c", TimeFields.Hour, TimeFields.Minute, TimeFields.Second, TimeFields.Milliseconds, separator); strncat(msgBufEntry, tempString, TRC_BUFFER_SIZE - strlen(msgBufEntry)); msgBufEntry[TRC_BUFFER_SIZE - 1] = 0; // // Add the process ID and thread ID // _snprintf(tempString, sizeof(tempString), TRC_PROC_FMT ":" TRC_PROC_FMT "%c", processId, threadId, separator); strncat(msgBufEntry, tempString, TRC_BUFFER_SIZE - strlen(msgBufEntry)); msgBufEntry[TRC_BUFFER_SIZE - 1] = 0; // // Add the rest. // _snprintf(tempString, sizeof(tempString), TRC_FUNC_FMT "%c" TRC_LINE_FMT "%c%s\n", TRC_FUNCNAME_LEN, TRC_FUNCNAME_LEN, funcName, separator, lineNumber, separator, traceString); strncat(msgBufEntry, tempString, TRC_BUFFER_SIZE - strlen(msgBufEntry)); msgBufEntry[TRC_BUFFER_SIZE - 1] = 0; msgBufEntry[TRC_BUFFER_SIZE - 2] = '\n'; // // Now that we have got the trace string, we need to write it out to // the debugger, if so configured. // if (TRC_WillTrace(traceLevel, fileName, lineNumber)) { DbgPrint(msgBufEntry); } } BOOL TRCPrefixMatch(PCHAR cpnt, PCHAR prefix) /*++ Routine Description: Internal function to compare a component name to a prefix. - assumes both are the same case - returns - TRUE if characters up to end of prefix match - FALSE otherwise Arguments: cpnt - filename prefix - characters to match Return Value: TRUE if matching, or FALSE --*/ { while ((*cpnt == *prefix) && (*prefix != 0)) { cpnt++; prefix++; } if (*prefix == 0) { return(TRUE); } return(FALSE); } BOOL TRC_WillTrace( IN ULONG traceLevel, IN PCHAR fileName, IN ULONG line ) /*++ Routine Description: Return whether tracing is turned on for a particular component. Arguments: traceComponent - Component producing this trace. traceLevel - Trace level (TRC_LEVEL_DBG, TRC_LEVEL_NRM, etc). fileName - Name of file being traced. line - Line of tracing call. Return Value: NA --*/ { BOOL rc = FALSE; int i; // // First of all check the trace level. If the trace level is error or // above then we trace regardless. // if ((traceLevel >= TRC_LEVEL_ERR) && (traceLevel != TRC_PROFILE_TRACE)) { rc = TRUE; goto ExitFunc; } if (traceLevel < TRC_Config.TraceLevel) { rc = FALSE; goto ExitFunc; } /************************************************************************/ /* Trace all lines if no prefixes are defined. */ /************************************************************************/ if (TRC_Config.Prefix[0].name[0] == 0) { rc = TRUE; goto ExitFunc; } /************************************************************************/ /* Some prefixes are defined - check whether this line matches any of */ /* them. */ /************************************************************************/ for (i = 0; i < TRC_MAX_PREFIX; i++) { if (TRC_Config.Prefix[i].name[0] == 0) { /****************************************************************/ /* End of list - break */ /****************************************************************/ break; } if (TRCPrefixMatch(fileName, TRC_Config.Prefix[i].name)) { /****************************************************************/ /* Found matching filename - is there a line number range */ /* specified? */ /****************************************************************/ if ((TRC_Config.Prefix[i].start == 0) && (TRC_Config.Prefix[i].end == 0)) { /************************************************************/ /* No line number range - trace this line */ /************************************************************/ rc = TRUE; goto ExitFunc; } /****************************************************************/ /* There's a line number range - see if this line falls within */ /* it. */ /****************************************************************/ if ((line >= TRC_Config.Prefix[i].start) && (line <= TRC_Config.Prefix[i].end)) { /************************************************************/ /* Line within prefix range - trace it. */ /************************************************************/ rc = TRUE; goto ExitFunc; } } } /* for */ /************************************************************************/ /* If we get here, we've searched the list of prefixes and failed to */ /* find a match - don't trace the line */ /************************************************************************/ rc = FALSE; ExitFunc: return rc; } #endif /* DBG */