📄 htrace.cpp
字号:
/********************************************************************
Module : HTrace.cpp Implementation of tracing routines.
Written 1998-2003 by Dmitri Leman
for an article in C/C++ journal about a tracing framework.
Purpose: Tracing framework allows inserting HTRACE and HTRACEK
tracing statements to applications and drivers.
Tracing messages may redirected to various output streams
without rebuilding the whole application.
To enable the trace, define TRACE_ in compiler settings.
To compile for NT kernel mode driver, add TRACER_NTDRIVER
definition. To compile with Java JNI support, add TRACE_JNI.
This file was compiled using Visual C++ 6.0 for WIN32 and NT
kernel mode,
g++ version egcs-2.91 for Red Hat Linux 6.1 on Pentium
********************************************************************/
#if defined(TRACER_NTDRIVER)
extern "C"
{
#include "ntddk.h"
//If the compiler cannot find ntddk.h,
//please download NT or 2000 DDK from www.microsoft.com/ddk
//and modify compiler settings to include ddk\inc directory
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define HAVE_EXCEPTIONS
#define HAVE_FILE_OUTPUT
}
#elif defined(CE_KERNEL_DRV)
#include <windows.h>
#include "CeApiTraps.h"
#elif defined(_WIN32_WCE)
#include <windows.h>
#define WINAPP
#define HAVE_FILE_OUTPUT
#elif defined(WIN32)
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#define WINAPP
#define HAVE_EXCEPTIONS
#define HAVE_FILE_OUTPUT
#elif defined(__linux__)
#if !defined(__i386__)
#error only Pentium supported
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unistd.h"
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <syslog.h>
#include <stdarg.h>
#define _vsnprintf vsnprintf
#define HAVE_FILE_OUTPUT
#else
#error "unknown platform"
#endif
#define TRACE_CPP
#include "HTrace.h"
#ifdef TRACE_JNI
#include "jni.h"
extern "C" void JNISetTotalMask
(ULONG p_dwTotal, ULONG p_ulConsole);
#endif
#ifdef TRACE_ //{
const TCHAR g_szMemMapFileName[] = _T("TraceMemMapFile");
const int g_iDefaultMemMapFileSize = 1024*1024;
#if !defined(_WIN32_WCE)
#pragma intrinsic(memset,memcpy,strlen,_tcscpy)
#endif
#if defined(__linux__)
long InterlockedExchangeAdd(long * p_plValue, long p_lAdd)
{
long l_lResult;
__asm__ __volatile__ (
"push %%EBX;"
"movl %1, %%EBX;"
"movl %2, %%EAX;"
"lock; xadd %%EAX, (%%EBX);"
"inc %%EAX;"
"mov %%EAX, %0;"
"pop %%EBX"
: "=g"(l_lResult) : "g"(p_plValue), "g"(p_lAdd) );
return l_lResult;
}
long InterlockedIncrement(long * p_plValue)
{
long l_lResult;
__asm__ __volatile__ (
"push %%EBX;"
"movl %1, %%EBX;"
"movl $1, %%EAX;"
"lock; xadd %%EAX, (%%EBX);"
"inc %%EAX;"
"mov %%EAX, %0;"
"pop %%EBX"
: "=g"(l_lResult) : "g"(p_plValue) );
return l_lResult;
}
long InterlockedDecrement(long * p_plValue)
{
long l_lResult;
__asm__ __volatile__ (
"push %%EBX;"
"movl %1, %%EBX;"
"movl $-1, %%EAX;"
"lock; xadd %%EAX, (%%EBX);"
"inc %%EAX;"
"mov %%EAX, %0;"
"pop %%EBX"
: "=g"(l_lResult) : "g"(p_plValue) );
return l_lResult;
}
static bool InterlockedExchangeAddUsingSemaphore(int p_iSemKey,
int & p_riSemID, int p_iAdd, int & p_riReturnPreviousValue);
#define __int64 long long
static ULONG GetTickCount()
{
clock_t l_Clock = clock();
HTRACE(16, "clock %d per sec %d", l_Clock, CLOCKS_PER_SEC);
return (ULONG)(((__int64)l_Clock) * 1000 / CLOCKS_PER_SEC);
}
static void _itoa(int p_iValue, char * p_pStr, int p_iRadix)
{
sprintf(p_pStr, (p_iRadix == 16)? "%x" : "%d", p_iValue);
}
#endif
#define countof(array) (sizeof(array)/sizeof(array[0]))
#if defined(_WIN32_WCE) && UNDER_CE < 400
long InterlockedExchangeAdd(long * p_plValue, long p_lAdd)
{
while(1)
{
long lOld1 = *p_plValue;
long lOld2 = InterlockedTestExchange
(p_plValue, lOld1, lOld1 + p_lAdd);
if(lOld1 == lOld2)
return lOld1;
//Some other thread interrupted us. Try again.
}
}
#endif
#ifdef HAVE_FILE_OUTPUT //{
/*
class HTraceFileImpl is a wrapper around platform-specific
routines to open,close, read and write a file
*/
class HTraceFileImpl
{
public:
void Cleanup();
ULONG OpenFile(LPCTSTR p_pszFileName, bool p_bWrite,
bool p_bPrependQuestionMarks,
#if defined(TRACER_NTDRIVER)
PUNICODE_STRING p_FileName
#else
void *
#endif
);
ULONG CloseFile();
bool IsOpened();
ULONG GetFileSize(OUT PLARGE_INTEGER p_pReturnSize);
ULONG ReadWriteFile(IN bool p_bWrite,
OUT void * p_lpBuffer,
IN ULONG p_dwNumberOfBytes,
IN OUT PLARGE_INTEGER p_pByteOffset,
OUT ULONG* p_pdwNumberOfBytesProcessed);
ULONG FlushBuffers();
protected:
HANDLE m_hFileHandle;
};//class HTraceFileImpl
/*
class HTraceFileLocal is useful as a local object in functions,
which need to open a file and close it before exiting.
*/
class HTraceFileLocal : public HTraceFileImpl
{
public:
HTraceFileLocal(){Cleanup();}
~HTraceFileLocal() {CloseFile();}
};//class HTraceFileLocal : public HTraceFileImpl
#endif //#ifdef HAVE_FILE_OUTPUT }
//T_TraceOutputStream is definition for trace output routines.
typedef bool T_TraceOutputStream
(ULONG p_dwMask, LPCTSTR p_pszMessage, int p_iLenChars);
//TraceOutput keeps necessary data for a trace output stream
struct TraceOutput
{
ULONG m_dwOutputID;
TCHAR * m_pszName;
ULONG m_dwEnabledGroups;
char m_szEnabledGroupsKeywords[256];
ULONG m_dwKeyWordModificationCounter;// equal to
//s_dwKeyWordModifCounter at modification time
T_TraceOutputStream * m_pOutputFunction;
};
//The following are various trace output functions.
//To add a new method of trace output just add a new constant
//to enum TraceOutputs in htrace.h, add a new routine here of
//type T_TraceOutputStream and add new line in s_Outputs array
bool OutputDebugMonitor
(ULONG p_dwMask, LPCTSTR p_pszMessage, int p_iLenChars);
bool OutputFile
(ULONG p_dwMask, LPCTSTR p_pszMessage, int p_iLenChars);
bool AddToTraceBuffer
(ULONG p_dwMask, LPCTSTR p_pszBuff, int p_iLenChars);
#if defined(TRACER_NTDRIVER)
bool AddToOutputLog
(ULONG p_dwMask, LPCTSTR p_pszString, int p_iLenChars);
#else
bool TraceMessageBox
(ULONG p_dwMask, LPCTSTR p_pszMessage,int p_iLenChars);
#if !defined(_WIN32_WCE)
bool OutputConsole
(ULONG p_dwMask, LPCTSTR p_pszBuff, int p_iLenChars);
#endif
#endif
TraceOutput s_Outputs[] = {
{TO_DebugMonitor, _T("DebugMonitor"),0, "",-1, OutputDebugMonitor},
{TO_File , _T("File") ,0, "",-1, OutputFile },
{TO_MemoryBuffer, _T("MemoryBuffer"),0, "",-1, AddToTraceBuffer },
#if defined(TRACER_NTDRIVER)
{TO_OutputLog , _T("OutputLog") ,0, "",-1, AddToOutputLog },
#else
{TO_MessageBox , _T("MessageBox") ,0, "",-1, TraceMessageBox },
#if !defined(_WIN32_WCE)
{TO_Console , _T("Console") ,0, "",-1, OutputConsole },
#endif
#endif
};//TraceOutput s_Outputs[]
#define NUM_STREAMS (countof(s_Outputs))
ULONG s_dwKeyWordModifCounter = 0;
static bool s_bInitialized = false;
//struct TraceImpl is a holder for various trace settings,
//current pointers to memory buffer, etc. Only one static
//instance will be created called s_Impl.
struct TraceImpl
{
void Clean()
{
m_BufferPointers.m_pGlobalHeader = NULL;
m_BufferPointers.m_pTextArea = NULL;
m_BufferPointers.m_dwTextAreaSize = 0;
m_BufferPointers.m_pGlobalFooter = NULL;
m_bBufferAllocated = false;
#if defined(WINAPP)
m_hFileMapping = NULL;
m_bBufferMapped = false;
m_hDeviceWithBuffer = INVALID_HANDLE_VALUE;
m_bMappedDriverBuffer = false;
m_iIOCTLToUnmapDriverBuffer = 0;
#endif
#if defined(__linux__)
m_iMemMapFile = -1;
m_iMappingSize = 0;
m_iSemKey = *((long*)"HTMF");
m_iSemID = 0;
m_bBufferMapped = false;
#endif
#ifdef TRACER_NTDRIVER
m_pDriverObject = NULL;
#else
#endif
m_dwFlushFileMask = 0;
m_pdwTotalMask = &m_dwTotalMask;
m_dwTotalMask = TG_Error;
m_dwConsoleMask = 0;
m_dwDebugMask = 0;
#ifdef HAVE_FILE_OUTPUT
m_File.Cleanup();
*m_szFileName = 0;
#endif
m_bAddTime = false;
m_bAddThread = false;
s_bInitialized = false;
}
void Free()
{
#ifdef HAVE_FILE_OUTPUT
m_File.CloseFile();
#endif
TraceFreeBuffer();
Clean();
}
bool TraceAssignGroupsToStream
(
ULONG p_dwTraceOutputs,
ULONG p_dwNewGroupFlags,
ULONG p_dwGroupFlagsToModify,
char * p_pszGroupKeyWord
);
bool TraceAllocateBuffer(int p_iSize);
bool TraceSetExternalBuffer
(GlobalTraceBufferHeader * p_pBuffer);
void AssignTraceBufferPtr
(GlobalTraceBufferHeader * p_pBuffer)
{
m_BufferPointers.m_dwTextAreaSize = (ULONG)
ReadSize(p_pBuffer->m_cSizeTextArea);
m_BufferPointers.m_pTextArea = (LPTSTR)(p_pBuffer+1);
int l_iFooterAddr = (int)
(((int)m_BufferPointers.m_pTextArea) +
m_BufferPointers.m_dwTextAreaSize);
//Align on 4 byte boundary
l_iFooterAddr += 3;
l_iFooterAddr &= ~3;
m_BufferPointers.m_pGlobalFooter =
(GlobalTraceBufferFooter *)l_iFooterAddr;
m_BufferPointers.m_pGlobalHeader = p_pBuffer;
//Start using shared mask:
m_pdwTotalMask = &m_BufferPointers.m_pGlobalFooter->
m_dwEnabledGroupsTotal;
}
static void SetTextAreaSizeHex
(char p_pszString[12], int p_iSize)
{
p_pszString[0] = ' ';
p_pszString[11] = '\n';
for(int i = 0; i < 10; i++)
{
p_pszString[10-i] = (p_iSize % 10) + '0';
p_iSize /= 10;
}
}
/*
ReadSize is a simplified version of atoi, which is only used
to read the size of the trace buffer stored in it's header.
It is always positive decimal number. We don't use a regular
atoi, because it may not be available on some platforms.
*/
static int ReadSize(char * p_pszString)
{
int l_iNumber = 0;
if(*p_pszString == ' ')
p_pszString++;
while(1)
{
char c = *(p_pszString++);
if(c < '0' || c > '9')
break;
l_iNumber = 10 * l_iNumber + (c - '0');
}
return l_iNumber;
}
#if defined(WINAPP)
bool CreateAndMapFile(LPCTSTR p_pszMemMapFilePath,
int p_iFileSize);
bool TraceAttachToNTDriverBuffer(LPCTSTR p_pszDeviceName,
int p_iIOCTLMapTraceBuffer, int p_iIOCTLUnMapTraceBuffer,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -