windows-nt/Source/XPSP1/NT/termsrv/common/trace/atrcapi.c
2020-09-26 16:20:57 +08:00

732 lines
30 KiB
C

/**MOD+**********************************************************************/
/* Module: atrcapi.c */
/* */
/* Purpose: External tracing functions */
/* */
/* Copyright(C) Microsoft Corporation 1996-7 */
/* */
/****************************************************************************/
/** Changes:
* $Log: Y:/logs/trc/atrcapi.c_v $
*
* Rev 1.12 22 Sep 1997 15:14:38 KH
* SFR1293: Fix Zippy16 file write errors when zippy starts before Ducati
*
* Rev 1.11 05 Sep 1997 10:34:54 SJ
* SFR1334: Zippy enhancements
*
* Rev 1.10 12 Aug 1997 09:45:28 MD
* SFR1002: Remove kernel tracing code
*
* Rev 1.9 04 Aug 1997 15:03:26 KH
* SFR1022: Cast file name length on sprintf call
*
* Rev 1.8 31 Jul 1997 19:39:30 SJ
* SFR1041: Port zippy to Win16
*
* Rev 1.7 16 Jul 1997 14:00:48 KH
* SFR1022: ALL functions are DCEXPORT
*
* Rev 1.6 11 Jul 1997 12:44:24 KH
* SFR1022: Add DCEXPORT to TRC_GetBuffer
*
* Rev 1.4 09 Jul 1997 17:59:12 AK
* SFR1016: Initial changes to support Unicode
*
* Rev 1.3 03 Jul 1997 13:27:24 AK
* SFR0000: Initial development completed
**/
/**MOD-**********************************************************************/
/****************************************************************************/
/* */
/* CONTENTS */
/* */
/* This file contains the DC-Groupware/NT tracing API. */
/* */
/****************************************************************************/
/* */
/* TRC_GetBuffer */
/* TRC_TraceBuffer */
/* TRC_GetConfig */
/* TRC_SetConfig */
/* TRC_TraceData */
/* TRC_GetTraceLevel */
/* TRC_ProfileTraceEnabled */
/* TRC_ResetTraceFiles */
/* */
/****************************************************************************/
/****************************************************************************/
/* Standard includes. */
/****************************************************************************/
#include <adcg.h>
/****************************************************************************/
/* Define TRC_FILE and TRC_GROUP. */
/****************************************************************************/
#define TRC_FILE "atrcapi"
#define TRC_GROUP TRC_GROUP_TRACE
/****************************************************************************/
/* Trace specific includes. */
/****************************************************************************/
#include <atrcapi.h>
#include <atrcint.h>
/****************************************************************************/
/* */
/* DATA */
/* */
/****************************************************************************/
#define DC_INCLUDE_DATA
#include <atrcdata.c>
#undef DC_INCLUDE_DATA
/****************************************************************************/
/* */
/* FUNCTIONS */
/* */
/****************************************************************************/
/**PROC+*********************************************************************/
/* TRC_GetBuffer(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
PDCTCHAR DCAPI DCEXPORT TRC_GetBuffer(DCVOID)
{
/************************************************************************/
/* Get the mutex. Note that we do not need to check that we are */
/* initialized in this function as this should have already been done. */
/************************************************************************/
TRCGrabMutex();
//
// Ensure null termination
//
trcpOutputBuffer[TRC_LINE_BUFFER_SIZE*sizeof(TCHAR) -1] = 0;
/************************************************************************/
/* Return a pointer to the trace buffer in the shared data memory */
/* mapped file. */
/************************************************************************/
return(trcpOutputBuffer);
} /* TRC_GetBuffer */
/**PROC+*********************************************************************/
/* TRC_TraceBuffer(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCVOID DCAPI DCEXPORT TRC_TraceBuffer(DCUINT traceLevel,
DCUINT traceComponent,
DCUINT lineNumber,
PDCTCHAR funcName,
PDCTCHAR fileName)
{
DCTCHAR fieldSeperator;
DCTCHAR frmtString[TRC_FRMT_BUFFER_SIZE] = {0};
DCTCHAR tempString[TRC_FRMT_BUFFER_SIZE] = {0};
DCUINT32 processId;
DCUINT32 threadId;
DCUINT length;
DC_TIME theTime;
HRESULT hr;
/************************************************************************/
/* First of all we need to decide if we are going to trace this line. */
/* */
/* Note that the decision to trace a line based on its level is taken */
/* in the TRACEX macro. */
/************************************************************************/
if (!TRCShouldTraceThis(traceComponent, traceLevel, fileName, lineNumber))
{
/********************************************************************/
/* Don't bother tracing this line. */
/********************************************************************/
DC_QUIT;
}
/************************************************************************/
/* We need to trace this line. First of all create the formatted */
/* output text string. Determine the field seperator for the trace */
/* line. Errors use a star (*), alerts a plus (+), asserts an */
/* exclamation mark (!) while normal and debug trace lines both use a */
/* space ( ). */
/************************************************************************/
switch(traceLevel)
{
case TRC_LEVEL_ASSERT:
{
fieldSeperator = '!';
}
break;
case TRC_LEVEL_ERR:
{
fieldSeperator = '*';
}
break;
case TRC_LEVEL_ALT:
{
fieldSeperator = '+';
}
break;
case TRC_LEVEL_NRM:
{
fieldSeperator = ' ';
}
break;
case TRC_LEVEL_DBG:
{
fieldSeperator = ' ';
}
break;
case TRC_PROFILE_TRACE:
{
fieldSeperator = ' ';
}
break;
default:
{
fieldSeperator = '?';
}
break;
}
/************************************************************************/
/* Get the current process and thread Ids. */
/************************************************************************/
processId = TRCGetCurrentProcessId();
threadId = TRCGetCurrentThreadId();
/************************************************************************/
/* Build the string to be printed out. First of all get the current */
/* time. */
/************************************************************************/
TRCGetCurrentTime(&theTime);
/************************************************************************/
/* Now format the string. Note that the function name is of variable */
/* length and given by <trcpConfig->funcNameLength>. */
/************************************************************************/
/************************************************************************/
/* Go through each optional field and decide whether to add it to the */
/* string or not. They are: */
/* TRC_OPT_PROCESS_ID */
/* TRC_OPT_THREAD_ID */
/* TRC_OPT_TIME_STAMP */
/* TRC_OPT_RELATIVE_TIME_STAMP */
/************************************************************************/
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_TIME_STAMP))
{
hr = StringCchPrintf(
tempString,
SIZE_TCHARS(tempString),
TRC_TIME_FMT _T("%c"),
theTime.hour,
theTime.min,
theTime.sec,
theTime.hundredths,
fieldSeperator
);
if (SUCCEEDED(hr)) {
hr = StringCchCat(frmtString, SIZE_TCHARS(frmtString), tempString);
if (FAILED(hr)) {
DC_QUIT;
}
}
else {
DC_QUIT;
}
}
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_PROCESS_ID))
{
hr = StringCchPrintf(tempString,
SIZE_TCHARS(tempString),
TRC_PROC_FMT,
processId);
if (SUCCEEDED(hr)) {
hr = StringCchCat(frmtString, SIZE_TCHARS(frmtString), tempString);
if (FAILED(hr)) {
DC_QUIT;
}
}
else {
DC_QUIT;
}
}
#ifdef OS_WIN32
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_THREAD_ID))
{
/********************************************************************/
/* Always put the colon before the thread ID so that, when only one */
/* of the IDs is present, it is clear which it is. */
/********************************************************************/
hr = StringCchPrintf(tempString,
SIZE_TCHARS(tempString),
_T(":") TRC_THRD_FMT,
threadId);
if (SUCCEEDED(hr)) {
hr = StringCchCat(frmtString, SIZE_TCHARS(frmtString), tempString);
if (FAILED(hr)) {
DC_QUIT;
}
}
else {
DC_QUIT;
}
}
#endif
#ifdef DC_OMIT
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_RELATIVE_TIME_STAMP))
{
/********************************************************************/
/* @@@ SJ - 090297 */
/* The idea is to show some low-order portion of the timestamp */
/* relative to the start time, in order to track timing issues. */
/********************************************************************/
}
#endif
hr = StringCchPrintf(tempString,
SIZE_TCHARS(tempString),
_T("%c") TRC_FUNC_FMT _T("%c") TRC_LINE_FMT _T("%c%s"),
fieldSeperator,
(DCINT)trcpConfig->funcNameLength,
(DCINT)trcpConfig->funcNameLength,
funcName,
fieldSeperator,
lineNumber,
fieldSeperator,
trcpOutputBuffer);
if (SUCCEEDED(hr)) {
hr = StringCchCat(frmtString, SIZE_TCHARS(frmtString), tempString);
if (FAILED(hr)) {
DC_QUIT;
}
}
else {
DC_QUIT;
}
/************************************************************************/
/* Add CR:LF to the end and update the length of the string. */
/************************************************************************/
hr = StringCchCat(frmtString, SIZE_TCHARS(frmtString), TRC_CRLF);
if (FAILED(hr)) {
DC_QUIT;
}
length = DC_TSTRLEN(frmtString) * sizeof(DCTCHAR);
/************************************************************************/
/* Now that we have got the trace string, we need to write it out. */
/************************************************************************/
TRCOutput(frmtString, length, traceLevel);
/************************************************************************/
/* If this is an assert trace then we need to reformat the string for */
/* use in the assert box. We must do this before we release the */
/* mutex. */
/************************************************************************/
hr = StringCchPrintf(frmtString,
SIZE_TCHARS(frmtString),
TRC_ASSERT_TEXT,
trcpOutputBuffer,
funcName,
fileName,
lineNumber);
if (FAILED(hr)) {
DC_QUIT;
}
/************************************************************************/
/* Decide if we need to do a stack trace. We must do this after */
/* reformating the string as we use the shared trace buffer - if we */
/* don't then we'll overwrite the original trace string! */
/************************************************************************/
if ((traceLevel >= TRC_LEVEL_ERR) && (traceLevel != TRC_PROFILE_TRACE))
{
TRCStackTrace(traceLevel);
}
DC_EXIT_POINT:
/************************************************************************/
/* Release the mutex. */
/************************************************************************/
TRCReleaseMutex();
/************************************************************************/
/* Now display the assert box - if an assert is already displayed then */
/* <TRCDisplayAssertBox> will just return. */
/************************************************************************/
if (TRC_LEVEL_ASSERT == traceLevel)
{
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_BREAK_ON_ASSERT))
{
//
// Break on assert so that we can actually get to see the assert
// in situations like stress where the user may not be
// watching for popups.
//
DebugBreak();
}
else
{
TRCDisplayAssertBox(frmtString);
}
}
/************************************************************************/
/* If this was an error level trace then we need to decide if we */
/* should beep, and then if we should break into the debugger. */
/************************************************************************/
if (TRC_LEVEL_ERR == traceLevel)
{
/********************************************************************/
/* Test if we should beep. */
/********************************************************************/
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_BEEP_ON_ERROR))
{
TRCBeep();
}
/********************************************************************/
/* Test if we should break into the debugger. Note that we have */
/* released the mutex, so other processes can continue to trace. */
/********************************************************************/
if (TEST_FLAG(trcpConfig->flags, TRC_OPT_BREAK_ON_ERROR))
{
TRCDebugBreak();
}
}
} /* TRC_TraceBuffer */
/**PROC+*********************************************************************/
/* TRC_GetConfig(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCBOOL DCAPI DCEXPORT TRC_GetConfig(PTRC_CONFIG pTraceConfig,
DCUINT length)
{
DCBOOL rc = TRUE;
/************************************************************************/
/* Check to ensure that the current state is valid. If it is not then */
/* just quit. */
/************************************************************************/
if ( trcpConfig == NULL )
{
TRCOpenSharedData();
}
else
{
TRCReadSharedDataConfig();
}
/************************************************************************/
/* Copy information from fixed structure to callers structure. */
/************************************************************************/
DC_MEMCPY(pTraceConfig,
trcpConfig,
DC_MIN(length, sizeof(TRC_CONFIG)));
DC_EXIT_POINT:
return(rc);
} /* TRC_GetConfig */
/**PROC+*********************************************************************/
/* TRC_SetConfig(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCBOOL DCAPI DCEXPORT TRC_SetConfig(PTRC_CONFIG pTraceConfig,
DCUINT length)
{
DCBOOL rc = TRUE;
DCUINT i;
DCUINT32 maxFileSize;
DCTCHAR fileNames[TRC_NUM_FILES][TRC_FILE_NAME_SIZE];
HRESULT hr;
/************************************************************************/
/* Check to ensure that the current state is valid. If it is not then */
/* just quit. */
/************************************************************************/
if ( trcpConfig == NULL )
{
TRCOpenSharedData();
}
else
{
TRCReadSharedDataConfig();
}
/************************************************************************/
/* We do not support dynamic modification of the maximum trace file */
/* size or of the trace file names. Therefore we store these before a */
/* change and overwrite the new values to ensure that they do not */
/* change. */
/************************************************************************/
maxFileSize = trcpConfig->maxFileSize;
for (i = 0; i < TRC_NUM_FILES; i++)
{
StringCchCopy(fileNames[i], TRC_FILE_NAME_SIZE,
trcpConfig->fileNames[i]);
}
/************************************************************************/
/* Copy information from fixed structure to callers structure. */
/************************************************************************/
DC_MEMCPY(trcpConfig,
pTraceConfig,
DC_MIN(length, sizeof(TRC_CONFIG)));
/************************************************************************/
/* Now restore the maximum trace file size and the trace file names. */
/************************************************************************/
trcpConfig->maxFileSize = maxFileSize;
for (i = 0; i < TRC_NUM_FILES; i++)
{
StringCchCopy(trcpConfig->fileNames[i],
SIZE_TCHARS(trcpConfig->fileNames[i]),
fileNames[i]);
}
/************************************************************************/
/* Split the prefix list. */
/************************************************************************/
TRCSplitPrefixes();
/************************************************************************/
/* Store the new configuration data. */
/************************************************************************/
TRCWriteSharedDataConfig();
DC_EXIT_POINT:
return(rc);
} /* TRC_SetConfig */
/**PROC+*********************************************************************/
/* TRC_TraceData(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCVOID DCAPI DCEXPORT TRC_TraceData(DCUINT traceLevel,
DCUINT traceComponent,
DCUINT lineNumber,
PDCTCHAR funcName,
PDCTCHAR fileName,
PDCUINT8 buffer,
DCUINT bufLength)
{
DCUINT i;
/************************************************************************/
/* If the trace checks fail then exit immediately. */
/************************************************************************/
if (!TRCShouldTraceThis(traceComponent, traceLevel, fileName, lineNumber))
{
/********************************************************************/
/* Don't bother tracing this data. */
/********************************************************************/
DC_QUIT;
}
/************************************************************************/
/* Truncate the length, if necessary. */
/************************************************************************/
if (bufLength > trcpConfig->dataTruncSize)
{
bufLength = (DCUINT)trcpConfig->dataTruncSize;
}
/************************************************************************/
/* TRC_TraceBuffer will decrement the mutex usage count for us - so we */
/* need to pre-increment it before calling TRC_BufferTrace. This */
/* ensures that we still have the mutex when we come to trace the data */
/* out. */
/************************************************************************/
TRCGrabMutex();
/************************************************************************/
/* Now trace out the description string. */
/************************************************************************/
TRC_TraceBuffer(traceLevel,
traceComponent,
lineNumber,
funcName,
fileName);
/************************************************************************/
/* Now trace the data portion. */
/************************************************************************/
for (i = 0; (i + 15) < bufLength; i += 16)
{
TRCDumpLine(buffer, 16, i, traceLevel);
buffer += 16;
}
/************************************************************************/
/* Check to see if we have a partial line to output. */
/************************************************************************/
if ((bufLength%16) > 0)
{
/********************************************************************/
/* Do partial line last. */
/********************************************************************/
TRCDumpLine(buffer, (bufLength%16), i, (DCUINT)traceLevel);
}
DC_EXIT_POINT:
/************************************************************************/
/* Finally free the mutex. */
/************************************************************************/
TRCReleaseMutex();
return;
} /* TRC_TraceData */
/**PROC+*********************************************************************/
/* TRC_GetTraceLevel(...) */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCUINT DCAPI DCEXPORT TRC_GetTraceLevel(DCVOID)
{
DCUINT32 rc = TRC_LEVEL_DIS;
/************************************************************************/
/* Check to ensure that the current state is valid. If it is not then */
/* just quit. */
/************************************************************************/
if (!TRCCheckState())
{
DC_QUIT;
}
/************************************************************************/
/* Get the current trace level. */
/************************************************************************/
rc = trcpConfig->traceLevel;
DC_EXIT_POINT:
return((DCUINT)rc);
} /* TRC_GetTraceLevel */
/**PROC+*********************************************************************/
/* TRC_ProfileTraceEnabled */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCBOOL DCAPI DCEXPORT TRC_ProfileTraceEnabled(DCVOID)
{
DCBOOL prfTrace = FALSE;
/************************************************************************/
/* Check to ensure that the current state is valid. If it is not then */
/* just quit. */
/************************************************************************/
if (!TRCCheckState())
{
DC_QUIT;
}
/************************************************************************/
/* Get the setting of the flag and return TRUE if function profile */
/* tracing is supported. */
/************************************************************************/
prfTrace = TEST_FLAG(trcpConfig->flags, TRC_OPT_PROFILE_TRACING);
DC_EXIT_POINT:
return(prfTrace);
} /* TRC_ProfileTraceEnabled */
/**PROC+*********************************************************************/
/* TRC_ResetTraceFiles */
/* */
/* See atrcapi.h for description. */
/**PROC-*********************************************************************/
DCBOOL DCAPI DCEXPORT TRC_ResetTraceFiles(DCVOID)
{
DCBOOL rc = TRUE;
/************************************************************************/
/* Check to ensure that the current state is valid. If it is not then */
/* just quit. */
/************************************************************************/
if (!TRCCheckState())
{
rc = FALSE;
DC_QUIT;
}
/************************************************************************/
/* Grab the mutex. */
/************************************************************************/
TRCGrabMutex();
/************************************************************************/
/* Call the OS specific function to reset the trace files. */
/************************************************************************/
TRCResetTraceFiles();
/************************************************************************/
/* Release the mutex. */
/************************************************************************/
TRCReleaseMutex();
DC_EXIT_POINT:
return(rc);
} /* TRC_ResetTraceFiles */
//
// Sprintf that will take care of truncating to the trace buffer size
//
#ifndef TRC_SAFER_SPRINTF
#define TRC_SAFER_SPRINTF
VOID TRCSaferSprintf(PDCTCHAR outBuf, UINT cchLen, const PDCTCHAR format,...)
{
HRESULT hr;
va_list vaArgs;
va_start(vaArgs, format);
hr = StringCchVPrintf(outBuf,
cchLen,
format,
vaArgs);
va_end(vaArgs);
}
#endif