- Naming style migrated to camel-case - P7lib logger sources added - Vcpkg manifest, CMake presets and build moved to root - SDL2, Vulkan and RmlUi dependencies added - Logger LOG macro added - Logger configuration - SDL2 window configuration - Vulkan configuration - RmlUi configuration - SDL event loop
2946 lines
97 KiB
C++
2946 lines
97 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// /
|
|
// 2012-2020 (c) Baical /
|
|
// /
|
|
// This library is free software; you can redistribute it and/or /
|
|
// modify it under the terms of the GNU Lesser General Public /
|
|
// License as published by the Free Software Foundation; either /
|
|
// version 3.0 of the License, or (at your option) any later version. /
|
|
// /
|
|
// This library is distributed in the hope that it will be useful, /
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU /
|
|
// Lesser General Public License for more details. /
|
|
// /
|
|
// You should have received a copy of the GNU Lesser General Public /
|
|
// License along with this library. /
|
|
// /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This file provide trace functionality /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Printf Type Field Characters: /
|
|
// http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx /
|
|
//Printf Type Field Characters: /
|
|
// http://msdn.microsoft.com/en-us/library/hf4y5e3w(v=vs.100).aspx /
|
|
//Size and Distance Specification /
|
|
// http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=vs.100).aspx /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#include "CommonClient.h"
|
|
#include "Trace.h"
|
|
#include <wchar.h>
|
|
#include <stdint.h>
|
|
|
|
#define RESET_UNDEFINED (0xFFFFFFFFUL)
|
|
#define RESET_FLAG_CHANNEL (0x1)
|
|
#define RESET_FLAG_TRACE (0x2)
|
|
|
|
#define FORMAT_CRASH_MESSAGE TM("Abnormal program termination, stack:")
|
|
#define FORMAT_STACK_MESSAGE TM(" ->[%02d] (0x%016I64X) %s, line %d")
|
|
#define FORMAT_FILE_UNKNOWN "-------"
|
|
#define FORMAT_FUNC_UNKNOWN "-------"
|
|
#define TRACE_SHARED_PREFIX TM("Trc_")
|
|
#define TRACE_EXTRA_CHUNKS (5)
|
|
|
|
#if !defined(UINTMAX_MAX)
|
|
typedef uint64_t uintmax_t;
|
|
#define UINTMAX_MAX 0xffffffffffffffffU
|
|
#endif
|
|
|
|
#if !defined(INTMAX_MAX)
|
|
typedef int64_t intmax_t;
|
|
#define INTMAX_MIN (-0x7fffffffffffffff - 1)
|
|
#define INTMAX_MAX 0x7fffffffffffffff
|
|
#endif
|
|
|
|
#define ADD_ARG(i_bType, i_bSize, oResult)\
|
|
{\
|
|
oResult = FALSE;\
|
|
if (m_dwArgs_Count < l_dwArgs_Max)\
|
|
{\
|
|
l_pArgs[m_dwArgs_Count].bType = i_bType;\
|
|
l_pArgs[m_dwArgs_Count].bSize = i_bSize;\
|
|
m_dwArgs_Count ++;\
|
|
oResult = TRUE;\
|
|
}\
|
|
else if ( m_dwArgs_Count >= l_dwArgs_Max )\
|
|
{\
|
|
tUINT32 l_dwLength = m_dwArgs_Count + 16;\
|
|
sP7Trace_Arg *l_pTMP = (sP7Trace_Arg*)i_rMemory.Reuse(CMemoryManager::eArguments,\
|
|
l_dwLength * sizeof(sP7Trace_Arg)\
|
|
);\
|
|
if (l_pTMP)\
|
|
{\
|
|
l_pArgs = l_pTMP;\
|
|
l_dwArgs_Max = l_dwLength;\
|
|
l_pArgs[m_dwArgs_Count].bType = i_bType;\
|
|
l_pArgs[m_dwArgs_Count].bSize = i_bSize;\
|
|
m_dwArgs_Count ++;\
|
|
oResult = TRUE;\
|
|
}\
|
|
}\
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//P7_Create_Client
|
|
P7_EXPORT IP7_Trace * __cdecl P7_Create_Trace(IP7_Client *i_pClient,
|
|
const tXCHAR *i_pName,
|
|
const stTrace_Conf *i_pConf
|
|
)
|
|
{
|
|
//Check parameters
|
|
if (i_pConf)
|
|
{
|
|
if ( ( (!i_pConf->qwTimestamp_Frequency)
|
|
&& (i_pConf->pTimestamp_Callback)
|
|
)
|
|
|| ( (i_pConf->qwTimestamp_Frequency)
|
|
&& (!i_pConf->pTimestamp_Callback)
|
|
)
|
|
)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CP7Trace *l_pReturn = new CP7Trace(i_pClient, i_pName, i_pConf);
|
|
|
|
//if not initialized - remove
|
|
if ( (l_pReturn)
|
|
&& (TRUE != l_pReturn->Is_Initialized())
|
|
)
|
|
{
|
|
l_pReturn->Release();
|
|
l_pReturn = NULL;
|
|
}
|
|
|
|
return static_cast<IP7_Trace *>(l_pReturn);
|
|
}//P7_Create_Client
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//P7_Get_Shared_Trace
|
|
P7_EXPORT IP7_Trace * __cdecl P7_Get_Shared_Trace(const tXCHAR *i_pName)
|
|
{
|
|
size_t l_szPadding = 16;
|
|
IP7_Trace *l_pReturn = NULL;
|
|
tUINT32 l_dwLen1 = PStrLen(TRACE_SHARED_PREFIX);
|
|
tUINT32 l_dwLen2 = PStrLen(i_pName);
|
|
tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + l_szPadding));
|
|
tUINT32 l_uTimeHi = 0;
|
|
tUINT32 l_uTimeLo = 0;
|
|
sObjShared l_stShared = {};
|
|
CShared::hSem l_hSem = SHARED_SEM_NULL;
|
|
|
|
|
|
CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo);
|
|
|
|
if (l_pName)
|
|
{
|
|
PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + l_szPadding, TRACE_SHARED_PREFIX);
|
|
PStrCpy(l_pName + l_dwLen1, l_dwLen2 + l_szPadding, i_pName);
|
|
|
|
if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250))
|
|
{
|
|
if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)))
|
|
{
|
|
if ( (l_stShared.uProcTimeHi == l_uTimeHi)
|
|
&& (l_stShared.uProcTimeLo == l_uTimeLo)
|
|
)
|
|
{
|
|
l_pReturn = static_cast<IP7_Trace *>(l_stShared.pPointer);
|
|
if (l_pReturn)
|
|
{
|
|
l_pReturn->Add_Ref();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CShared::UnLink(l_pName);
|
|
}
|
|
}
|
|
|
|
CShared::UnLock(l_hSem);
|
|
}
|
|
|
|
free(l_pName);
|
|
l_pName = NULL;
|
|
}
|
|
|
|
return l_pReturn;
|
|
}//P7_Get_Shared_Trace
|
|
|
|
} //extern "C"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
enum ePrefix_Type
|
|
{
|
|
EPREFIX_TYPE_I64 = 0,
|
|
EPREFIX_TYPE_I32 ,
|
|
EPREFIX_TYPE_LL ,
|
|
EPREFIX_TYPE_L ,
|
|
EPREFIX_TYPE_HH ,
|
|
EPREFIX_TYPE_H ,
|
|
EPREFIX_TYPE_I ,
|
|
EPREFIX_TYPE_W ,
|
|
EPREFIX_TYPE_J ,
|
|
EPREFIX_TYPE_UNKNOWN
|
|
};
|
|
|
|
struct sPrefix_Desc
|
|
{
|
|
const tXCHAR *pPrefix;
|
|
tUINT32 dwLen;
|
|
ePrefix_Type eType;
|
|
};
|
|
|
|
|
|
|
|
//the order of strings IS VERY important, because we will search for first match
|
|
static const sPrefix_Desc g_pPrefixes[] = { {TM("I64"), 3, EPREFIX_TYPE_I64 },
|
|
{TM("I32"), 3, EPREFIX_TYPE_I32 },
|
|
{TM("ll"), 2, EPREFIX_TYPE_LL },
|
|
{TM("hh"), 2, EPREFIX_TYPE_HH },
|
|
{TM("h"), 1, EPREFIX_TYPE_H },
|
|
{TM("l"), 1, EPREFIX_TYPE_L },
|
|
{TM("I"), 1, EPREFIX_TYPE_I },
|
|
{TM("z"), 1, EPREFIX_TYPE_I },
|
|
{TM("t"), 1, EPREFIX_TYPE_I },
|
|
{TM("w"), 1, EPREFIX_TYPE_W },
|
|
{TM("j"), 1, EPREFIX_TYPE_J },
|
|
{TM("?"), 0, EPREFIX_TYPE_UNKNOWN}
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Prefix
|
|
const sPrefix_Desc *Get_Prefix(const tXCHAR *i_pFormat)
|
|
{
|
|
const sPrefix_Desc *l_pPrefix = &g_pPrefixes[0];
|
|
const sPrefix_Desc *l_pReturn = NULL;
|
|
|
|
while (l_pPrefix->dwLen)
|
|
{
|
|
if (0 == PStrNCmp(i_pFormat, l_pPrefix->pPrefix, l_pPrefix->dwLen))
|
|
{
|
|
l_pReturn = l_pPrefix;
|
|
break;
|
|
}
|
|
|
|
l_pPrefix ++;
|
|
}
|
|
|
|
return l_pReturn;
|
|
}// Get_Prefix
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CP7Trace_Desc
|
|
CP7Trace_Desc::CP7Trace_Desc(CMemoryManager &i_rMemory,
|
|
tUINT16 i_wID,
|
|
tUINT16 i_wLine,
|
|
tUINT16 i_wModuleID,
|
|
const char *i_pFile,
|
|
const char *i_pFunction,
|
|
const tXCHAR **i_pFormat,
|
|
tKeyType i_pKeys[P7TRACE_KEY_LENGTH],
|
|
tUINT32 i_dwFlags
|
|
)
|
|
: m_wID(i_wID)
|
|
, m_wModuleID(i_wModuleID)
|
|
, m_dwResets(RESET_UNDEFINED)
|
|
, m_dwSize(0)
|
|
, m_pBuffer(NULL)
|
|
|
|
, m_pBlocks(NULL)
|
|
, m_dwBlocks_Count(0)
|
|
, m_pArgs(NULL)
|
|
, m_dwArgs_Count(0)
|
|
|
|
, m_bInitialized(TRUE)
|
|
{
|
|
UNUSED_ARG(i_dwFlags);
|
|
|
|
tUINT32 l_dwFile_Size = 0;
|
|
tUINT32 l_dwFunc_Size = 0;
|
|
tUINT32 l_dwForm_Size = 0;
|
|
const tXCHAR *l_pFormat = *i_pFormat;
|
|
sP7Trace_Arg *l_pArgs = NULL;
|
|
tUINT32 l_dwArgs_Max = 0;
|
|
tUINT8 l_bSize = 0;
|
|
|
|
m_bInitialized = (NULL != l_pFormat);
|
|
|
|
m_pKey[0] = i_pKeys[0];
|
|
m_pKey[1] = i_pKeys[1];
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
ePrefix_Type l_ePrefix = EPREFIX_TYPE_UNKNOWN;
|
|
const tXCHAR *l_pIterator = l_pFormat;
|
|
tBOOL l_bPercent = FALSE;
|
|
|
|
while ( (*l_pIterator)
|
|
&& (m_bInitialized)
|
|
)
|
|
{
|
|
if (FALSE == l_bPercent)
|
|
{
|
|
if (TM('%') == (*l_pIterator))
|
|
{
|
|
//we can get "%%" in this case we should ignore "%"
|
|
l_bPercent = ! l_bPercent;//TRUE;
|
|
l_ePrefix = EPREFIX_TYPE_UNKNOWN;
|
|
l_bSize = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (*l_pIterator)
|
|
{
|
|
case TM('*'):
|
|
{
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
l_bSize = 1;
|
|
break;
|
|
}
|
|
case TM('I'):
|
|
case TM('l'):
|
|
case TM('h'):
|
|
case TM('w'):
|
|
case TM('z'):
|
|
case TM('j'):
|
|
case TM('t'):
|
|
{
|
|
const sPrefix_Desc *l_pPrefix = Get_Prefix(l_pIterator);
|
|
if (l_pPrefix)
|
|
{
|
|
l_ePrefix = l_pPrefix->eType;
|
|
|
|
if (1 < l_pPrefix->dwLen)
|
|
{
|
|
l_pIterator += (l_pPrefix->dwLen - 1);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case TM('d'):
|
|
case TM('b'):
|
|
case TM('i'):
|
|
case TM('o'):
|
|
case TM('u'):
|
|
case TM('x'):
|
|
case TM('X'):
|
|
{
|
|
if (EPREFIX_TYPE_UNKNOWN == l_ePrefix)
|
|
{
|
|
//4 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
}
|
|
else if ( (EPREFIX_TYPE_LL == l_ePrefix)
|
|
|| (EPREFIX_TYPE_I64 == l_ePrefix)
|
|
)
|
|
{
|
|
//8 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized);
|
|
}
|
|
else if (EPREFIX_TYPE_H == l_ePrefix)
|
|
{
|
|
//2 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT16, SIZE_OF_ARG(tUINT16), m_bInitialized);
|
|
}
|
|
else if (EPREFIX_TYPE_HH == l_ePrefix)
|
|
{
|
|
//1 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT8, SIZE_OF_ARG(tUINT8), m_bInitialized);
|
|
}
|
|
else if (EPREFIX_TYPE_L == l_ePrefix)
|
|
{
|
|
#if defined(__linux__)
|
|
#ifdef GTX64
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized);
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
#endif
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
#endif
|
|
}
|
|
else if (EPREFIX_TYPE_I32 == l_ePrefix)
|
|
{
|
|
//4 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
}
|
|
else if (EPREFIX_TYPE_I == l_ePrefix)
|
|
{
|
|
#ifdef GTX64
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized);
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
#endif
|
|
}
|
|
else if (EPREFIX_TYPE_J == l_ePrefix)
|
|
{
|
|
//8 bytes integer for most of the platforms, truncate for others
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INTMAX, SIZE_OF_ARG(uintmax_t), m_bInitialized);
|
|
}
|
|
else //by default
|
|
{
|
|
//4 bytes integer
|
|
ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized);
|
|
}
|
|
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
case TM('s'):
|
|
case TM('S'):
|
|
{
|
|
if (EPREFIX_TYPE_H == l_ePrefix)
|
|
{
|
|
ADD_ARG(P7TRACE_ARG_TYPE_STRA, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
}
|
|
#ifdef UTF8_ENCODING //%S NOT PORTABLE, DO NOT USE IT!, use %ls or %hs
|
|
else if (TM('S') == (*l_pIterator))
|
|
{
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR32, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
}
|
|
#else
|
|
else if (TM('S') == (*l_pIterator))
|
|
{
|
|
ADD_ARG(P7TRACE_ARG_TYPE_STRA, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
}
|
|
#endif
|
|
else if (EPREFIX_TYPE_L == l_ePrefix)
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR32, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR16, l_bSize, m_bInitialized); //SIZE_OF_ARG(wchar_t*)
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR8, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR16, l_bSize, m_bInitialized); //SIZE_OF_ARG(wchar_t*)
|
|
#endif
|
|
}
|
|
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
//case TM('n'): ignored, not supported
|
|
case TM('p'):
|
|
{
|
|
ADD_ARG(P7TRACE_ARG_TYPE_PVOID, SIZE_OF_ARG(void*), m_bInitialized);
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
case TM('e'):
|
|
case TM('E'):
|
|
case TM('f'):
|
|
case TM('g'):
|
|
case TM('G'):
|
|
case TM('a'):
|
|
case TM('A'):
|
|
{
|
|
//8 bytes double
|
|
ADD_ARG(P7TRACE_ARG_TYPE_DOUBLE, SIZE_OF_ARG(tDOUBLE), m_bInitialized);
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
case TM('c'):
|
|
case TM('C'):
|
|
{
|
|
if (EPREFIX_TYPE_H == l_ePrefix)
|
|
{
|
|
//1 bytes character
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized);
|
|
}
|
|
else if (EPREFIX_TYPE_L == l_ePrefix)
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR32, SIZE_OF_ARG(wchar_t), m_bInitialized);
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR16, SIZE_OF_ARG(wchar_t), m_bInitialized);
|
|
#endif
|
|
}
|
|
else if (TM('c') == (*l_pIterator))
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized);
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR16, SIZE_OF_ARG(wchar_t), m_bInitialized);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//1 bytes character
|
|
ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized);
|
|
}
|
|
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
case TM('%'):
|
|
{
|
|
l_bPercent = FALSE;
|
|
break;
|
|
}
|
|
} //switch (*l_pIterator)
|
|
|
|
if ( (TM('0') <= (*l_pIterator))
|
|
&& (TM('9') >= (*l_pIterator))
|
|
)
|
|
{
|
|
l_bSize = 1;
|
|
}
|
|
}
|
|
|
|
l_pIterator ++;
|
|
} //while ( (*l_pIterator)
|
|
|
|
//if (FALSE == m_bInitialized)
|
|
//{
|
|
// m_dwArgs_Count = 0;
|
|
// l_pFormat = TM("WRONG TRACE ARGUMENTS !");
|
|
//}
|
|
} //if (m_bInitialized)
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
m_dwSize = sizeof(sP7Trace_Format);
|
|
|
|
if (l_pArgs)
|
|
{
|
|
m_dwSize += sizeof(sP7Trace_Arg) * m_dwArgs_Count;
|
|
}
|
|
|
|
if (i_pFile)
|
|
{
|
|
l_dwFile_Size += (tUINT32)strlen(i_pFile);
|
|
}
|
|
l_dwFile_Size ++; //last 0
|
|
|
|
if (i_pFunction)
|
|
{
|
|
l_dwFunc_Size += (tUINT32)strlen(i_pFunction);
|
|
}
|
|
l_dwFunc_Size ++; //last 0
|
|
|
|
l_dwForm_Size = (PUStrLen(l_pFormat) + 1) * sizeof(tWCHAR);
|
|
m_dwSize += l_dwForm_Size + l_dwFunc_Size + l_dwFile_Size;
|
|
|
|
|
|
m_pBuffer = (tUINT8*)i_rMemory.Alloc(m_dwSize);
|
|
if (NULL == m_pBuffer)
|
|
{
|
|
m_bInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//calculate stack blocks max size
|
|
if ( (m_bInitialized)
|
|
&& (l_pArgs)
|
|
)
|
|
{
|
|
tBOOL l_bCumulative = FALSE;
|
|
|
|
//allocate blocks for every variable
|
|
m_dwBlocks_Count = 0;
|
|
m_pBlocks = (tINT32*)i_rMemory.Alloc(sizeof(tINT32) * (m_dwArgs_Count));
|
|
|
|
if (m_pBlocks) //fill the blocks
|
|
{
|
|
memset(m_pBlocks, 0, sizeof(tINT32) * m_dwArgs_Count);
|
|
l_bCumulative = FALSE;
|
|
|
|
for (tUINT32 l_dwI = 0; l_dwI < m_dwArgs_Count; l_dwI++)
|
|
{
|
|
if (P7TRACE_ARG_TYPE_PVOID >= l_pArgs[l_dwI].bType) //most probable case
|
|
{
|
|
if (FALSE == l_bCumulative)
|
|
{
|
|
m_dwBlocks_Count ++;
|
|
l_bCumulative = TRUE;
|
|
}
|
|
|
|
m_pBlocks[m_dwBlocks_Count - 1] += l_pArgs[l_dwI].bSize;
|
|
}
|
|
else if (P7TRACE_ARG_TYPE_USTR16 == l_pArgs[l_dwI].bType)
|
|
{
|
|
if (0 == l_pArgs[l_dwI].bSize)
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_USTRING16;
|
|
}
|
|
else
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_WSTRING_FIX;
|
|
l_pArgs[l_dwI].bSize = 0;
|
|
}
|
|
|
|
m_dwBlocks_Count ++;
|
|
l_bCumulative = FALSE;
|
|
}
|
|
else if ( (P7TRACE_ARG_TYPE_STRA == l_pArgs[l_dwI].bType)
|
|
|| (P7TRACE_ARG_TYPE_USTR8 == l_pArgs[l_dwI].bType)
|
|
)
|
|
{
|
|
if (0 == l_pArgs[l_dwI].bSize)
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_ASTRING;
|
|
}
|
|
else
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_ASTRING_FIX;
|
|
l_pArgs[l_dwI].bSize = 0;
|
|
}
|
|
|
|
m_dwBlocks_Count ++;
|
|
l_bCumulative = FALSE;
|
|
}
|
|
else if (P7TRACE_ARG_TYPE_USTR32 == l_pArgs[l_dwI].bType)
|
|
{
|
|
if (0 == l_pArgs[l_dwI].bSize)
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_USTRING32;
|
|
}
|
|
else
|
|
{
|
|
m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_WSTRING_FIX;
|
|
l_pArgs[l_dwI].bSize = 0;
|
|
}
|
|
|
|
m_dwBlocks_Count ++;
|
|
l_bCumulative = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (FALSE == l_bCumulative)
|
|
{
|
|
m_dwBlocks_Count ++;
|
|
l_bCumulative = TRUE;
|
|
}
|
|
|
|
m_pBlocks[m_dwBlocks_Count - 1] += l_pArgs[l_dwI].bSize;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
//forming trace format header with all related info
|
|
if (m_bInitialized)
|
|
{
|
|
tUINT32 l_dwOffset = 0;
|
|
|
|
sP7Trace_Format *l_pHeader_Desc = (sP7Trace_Format *)(m_pBuffer + l_dwOffset);
|
|
|
|
INIT_EXT_HEADER(l_pHeader_Desc->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DESC, m_dwSize);
|
|
//l_pHeader_Desc->sCommon.dwSize = m_dwSize;
|
|
//l_pHeader_Desc->sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_pHeader_Desc->sCommon.dwSubType = EP7TRACE_TYPE_DESC;
|
|
|
|
l_pHeader_Desc->wArgs_Len = (tUINT16)m_dwArgs_Count;
|
|
l_pHeader_Desc->wID = i_wID;
|
|
l_pHeader_Desc->wLine = i_wLine;
|
|
l_pHeader_Desc->wModuleID = i_wModuleID;
|
|
l_dwOffset += sizeof(sP7Trace_Format);
|
|
|
|
|
|
if (l_pArgs)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset,
|
|
l_pArgs,
|
|
sizeof(sP7Trace_Arg) * m_dwArgs_Count
|
|
);
|
|
m_pArgs = (sP7Trace_Arg*)(m_pBuffer + l_dwOffset);
|
|
l_dwOffset += sizeof(sP7Trace_Arg) * m_dwArgs_Count;
|
|
}
|
|
|
|
//we do not verify address of l_pFormat because we do it before
|
|
PUStrCpy((tWCHAR*)(m_pBuffer + l_dwOffset),
|
|
(m_dwSize - l_dwOffset) / sizeof(tWCHAR),
|
|
l_pFormat
|
|
);
|
|
|
|
l_dwOffset += l_dwForm_Size;
|
|
|
|
if (i_pFile)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset, i_pFile, l_dwFile_Size);
|
|
l_dwOffset += l_dwFile_Size;
|
|
}
|
|
else
|
|
{
|
|
m_pBuffer[l_dwOffset ++] = 0;
|
|
}
|
|
|
|
if (i_pFunction)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset, i_pFunction, l_dwFunc_Size);
|
|
l_dwOffset += l_dwFunc_Size;
|
|
}
|
|
else
|
|
{
|
|
m_pBuffer[l_dwOffset ++] = 0;
|
|
}
|
|
}
|
|
} // CP7Trace_Desc
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CP7Trace_Desc
|
|
CP7Trace_Desc::CP7Trace_Desc(CMemoryManager &i_rMemory,
|
|
tUINT16 i_wID,
|
|
tUINT16 i_wLine,
|
|
tUINT16 i_wModuleID,
|
|
const tXCHAR *i_pFile,
|
|
const tXCHAR *i_pFunction,
|
|
tKeyType i_pKeys[P7TRACE_KEY_LENGTH]
|
|
)
|
|
: m_wID(i_wID)
|
|
, m_wModuleID(i_wModuleID)
|
|
, m_dwResets(RESET_UNDEFINED)
|
|
, m_dwSize(0)
|
|
, m_pBuffer(NULL)
|
|
|
|
, m_pBlocks(NULL)
|
|
, m_dwBlocks_Count(0)
|
|
|
|
, m_pArgs(NULL)
|
|
, m_dwArgs_Count(0)
|
|
|
|
, m_bInitialized(TRUE)
|
|
{
|
|
const tXCHAR *l_pFormat = TM("%s");
|
|
tUINT32 l_dwFile_Size = 0;
|
|
tUINT32 l_dwFunc_Size = 0;
|
|
tUINT32 l_dwForm_Size = 0;
|
|
char *l_pFile = NULL;
|
|
char *l_pFunction = NULL;
|
|
sP7Trace_Arg *l_pArgs = NULL;
|
|
tUINT32 l_dwArgs_Max = 0;
|
|
|
|
if (i_pKeys)
|
|
{
|
|
m_pKey[0] = i_pKeys[0];
|
|
m_pKey[1] = i_pKeys[1];
|
|
}
|
|
else
|
|
{
|
|
m_pKey[0] = 0;
|
|
m_pKey[1] = 0;
|
|
}
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR8, 0, m_bInitialized); //SIZE_OF_ARG(char*)
|
|
#else
|
|
ADD_ARG(P7TRACE_ARG_TYPE_USTR16, 0, m_bInitialized); //SIZE_OF_ARG(wchar_t*)
|
|
#endif
|
|
} //if (m_bInitialized)
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
m_dwSize = sizeof(sP7Trace_Format);
|
|
|
|
if (l_pArgs)
|
|
{
|
|
m_dwSize += sizeof(sP7Trace_Arg) * m_dwArgs_Count;
|
|
}
|
|
|
|
if (i_pFile)
|
|
{
|
|
l_dwFile_Size = (tUINT32)PStrLen(i_pFile);
|
|
|
|
#ifdef UTF8_ENCODING
|
|
l_pFile = const_cast<char*>(i_pFile);
|
|
#else
|
|
l_dwFile_Size *= 5;
|
|
l_pFile = (char*)i_rMemory.Reuse(CMemoryManager::eFileName, l_dwFile_Size);
|
|
l_dwFile_Size = Convert_UTF16_To_UTF8((const tWCHAR *)i_pFile,
|
|
l_pFile,
|
|
l_dwFile_Size
|
|
);
|
|
#endif
|
|
}
|
|
l_dwFile_Size ++; //last 0
|
|
|
|
if (i_pFunction)
|
|
{
|
|
l_dwFunc_Size = (tUINT32)PStrLen(i_pFunction);
|
|
|
|
#ifdef UTF8_ENCODING
|
|
l_pFunction = const_cast<char*>(i_pFunction);
|
|
#else
|
|
l_dwFunc_Size *= 5;
|
|
l_pFunction = (char*)i_rMemory.Reuse(CMemoryManager::eFunctionName, l_dwFunc_Size);
|
|
l_dwFunc_Size = Convert_UTF16_To_UTF8((const tWCHAR *)i_pFunction,
|
|
l_pFunction,
|
|
l_dwFunc_Size
|
|
);
|
|
#endif
|
|
}
|
|
l_dwFunc_Size ++; //last 0
|
|
|
|
l_dwForm_Size = (PUStrLen(l_pFormat) + 1) * sizeof(tWCHAR);
|
|
m_dwSize += l_dwForm_Size + l_dwFunc_Size + l_dwFile_Size;
|
|
|
|
m_pBuffer = (tUINT8*)i_rMemory.Alloc(m_dwSize);
|
|
if (NULL == m_pBuffer)
|
|
{
|
|
m_bInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
tUINT32 l_dwOffset = 0;
|
|
sP7Trace_Format *l_pHeader_Desc = (sP7Trace_Format *)(m_pBuffer + l_dwOffset);
|
|
|
|
INIT_EXT_HEADER(l_pHeader_Desc->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DESC, m_dwSize);
|
|
//l_pHeader_Desc->sCommon.dwSize = m_dwSize;
|
|
//l_pHeader_Desc->sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_pHeader_Desc->sCommon.dwSubType = EP7TRACE_TYPE_DESC;
|
|
|
|
l_pHeader_Desc->wArgs_Len = (tUINT16)m_dwArgs_Count;
|
|
l_pHeader_Desc->wID = i_wID;
|
|
l_pHeader_Desc->wLine = i_wLine;
|
|
l_pHeader_Desc->wModuleID = i_wModuleID;
|
|
l_dwOffset += sizeof(sP7Trace_Format);
|
|
|
|
if (l_pArgs)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset,
|
|
l_pArgs,
|
|
sizeof(sP7Trace_Arg) * m_dwArgs_Count
|
|
);
|
|
l_dwOffset += sizeof(sP7Trace_Arg) * m_dwArgs_Count;
|
|
}
|
|
|
|
//I don't verify address of l_pFormat because I did it before
|
|
PUStrCpy((tWCHAR*)(m_pBuffer + l_dwOffset),
|
|
(m_dwSize - l_dwOffset) / sizeof(tWCHAR),
|
|
l_pFormat
|
|
);
|
|
|
|
l_dwOffset += l_dwForm_Size;
|
|
|
|
if (l_pFile)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset, l_pFile, l_dwFile_Size);
|
|
l_dwOffset += l_dwFile_Size;
|
|
}
|
|
else
|
|
{
|
|
m_pBuffer[l_dwOffset ++] = 0;
|
|
}
|
|
|
|
if (l_pFunction)
|
|
{
|
|
memcpy(m_pBuffer + l_dwOffset, l_pFunction, l_dwFunc_Size);
|
|
l_dwOffset += l_dwFunc_Size;
|
|
}
|
|
else
|
|
{
|
|
m_pBuffer[l_dwOffset ++] = 0;
|
|
}
|
|
}
|
|
|
|
} // CP7Trace_Desc
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Is_Initialized
|
|
tBOOL CP7Trace_Desc::Is_Initialized()
|
|
{
|
|
return m_bInitialized;
|
|
}// Is_Initialized
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Buffer
|
|
tUINT8 *CP7Trace_Desc::Get_Buffer(tUINT32 *o_pSize)
|
|
{
|
|
if (NULL != o_pSize)
|
|
{
|
|
*o_pSize = m_dwSize;
|
|
}
|
|
return m_pBuffer;
|
|
}// Get_Buffer
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Blocks
|
|
tINT32 *CP7Trace_Desc::Get_Blocks(tUINT32 *o_pCount)
|
|
{
|
|
if (NULL == o_pCount)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
*o_pCount = m_dwBlocks_Count;
|
|
|
|
return m_pBlocks;
|
|
}// Get_Blocks
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Set_Resets
|
|
void CP7Trace_Desc::Set_Resets(tUINT32 i_dwResets)
|
|
{
|
|
m_dwResets = i_dwResets;
|
|
}// Set_Resets
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Resets
|
|
tUINT32 CP7Trace_Desc::Get_Resets()
|
|
{
|
|
return m_dwResets;
|
|
}// Get_Resets
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Arguments_Count
|
|
tUINT32 CP7Trace_Desc::Get_Arguments_Count()
|
|
{
|
|
return m_dwArgs_Count;
|
|
}// Get_Arguments_Count
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Arguments
|
|
const sP7Trace_Arg *CP7Trace_Desc::Get_Arguments(tUINT32 &o_rCount)
|
|
{
|
|
o_rCount = m_dwArgs_Count;
|
|
return m_pArgs;
|
|
}// Get_Arguments
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Is_Equal
|
|
GASSERT(P7TRACE_KEY_LENGTH == 2);
|
|
tBOOL CP7Trace_Desc::Is_Equal(tKeyType *i_pKey)
|
|
{
|
|
return ((i_pKey[0] == m_pKey[0]) && (i_pKey[1] == m_pKey[1]));
|
|
}// Is_Equal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Is_Greater (m_pKey > i_pKey) == TRUE
|
|
GASSERT(P7TRACE_KEY_LENGTH == 2);
|
|
tBOOL CP7Trace_Desc::Is_Greater(tKeyType *i_pKey)
|
|
{
|
|
if (i_pKey[0] < m_pKey[0])
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if ((i_pKey[0] == m_pKey[0]) && (i_pKey[1] < m_pKey[1]))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}// Is_Greater
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_ID
|
|
tUINT16 CP7Trace_Desc::Get_ID()
|
|
{
|
|
return m_wID;
|
|
} //Get_ID
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_MID
|
|
tUINT16 CP7Trace_Desc::Get_MID()
|
|
{
|
|
return m_wModuleID;
|
|
} // Get_MID
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CP7Trace
|
|
CP7Trace::CP7Trace(IP7_Client *i_pClient,
|
|
const tXCHAR *i_pName,
|
|
const stTrace_Conf *i_pConf)
|
|
: m_lReference(1)
|
|
, m_dwSequence(0)
|
|
, m_pClient(i_pClient)
|
|
, m_dwChannel_ID(0)
|
|
, m_wDesc_Tree_ID(P7_TRACE_DESC_HARDCODED_COUNT)
|
|
, m_dwLast_ID(0)
|
|
, m_bInitialized(TRUE)
|
|
, m_bActive(TRUE)
|
|
, m_eVerbosity(EP7TRACE_LEVEL_TRACE)
|
|
, m_pChk_Head(NULL)
|
|
, m_pChk_Tail(NULL)
|
|
, m_pChk_Curs(NULL)
|
|
, m_dwChk_Count(0)
|
|
, m_dwChk_Size(0)
|
|
, m_bIs_Channel(FALSE)
|
|
, m_dwFlags(0)
|
|
, m_wLast_ModuleID(1)
|
|
, m_hShared(NULL)
|
|
, m_cMemory(10240)
|
|
, m_pVargs(NULL)
|
|
, m_szVargs(0)
|
|
{
|
|
if (i_pConf)
|
|
{
|
|
m_sConf = *i_pConf;
|
|
}
|
|
else
|
|
{
|
|
memset(&m_sConf, 0, sizeof(m_sConf));
|
|
}
|
|
|
|
memset(&m_sCS, 0, sizeof(m_sCS));
|
|
|
|
LOCK_CREATE(m_sCS);
|
|
|
|
memset(&m_sHeader_Info, 0, sizeof(m_sHeader_Info));
|
|
memset(&m_sHeader_Data, 0, sizeof(m_sHeader_Data));
|
|
memset(&m_sHeader_Utc, 0, sizeof(m_sHeader_Utc));
|
|
memset(m_pDesc_Array, 0, sizeof(m_pDesc_Array));
|
|
|
|
m_sStatus.bConnected = TRUE;
|
|
m_sStatus.dwResets = 0;
|
|
|
|
if (NULL == m_pClient)
|
|
{
|
|
m_bInitialized = FALSE;
|
|
P7_Set_Last_Error(eP7_Error_NoClient);
|
|
}
|
|
else
|
|
{
|
|
const tXCHAR *l_pVerbosiry = m_pClient->Get_Argument(CLIENT_COMMAND_TRACE_VERBOSITY);
|
|
if (l_pVerbosiry)
|
|
{
|
|
eP7Trace_Level l_eVerbosity = (eP7Trace_Level)PStrToInt(l_pVerbosiry);
|
|
if ( (l_eVerbosity < EP7TRACE_LEVEL_COUNT)
|
|
&& (l_eVerbosity >= EP7TRACE_LEVEL_TRACE)
|
|
)
|
|
{
|
|
m_eVerbosity = l_eVerbosity;
|
|
}
|
|
}
|
|
|
|
m_pClient->Add_Ref();
|
|
}
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
m_bInitialized = Inc_Chunks(256);
|
|
|
|
if (!m_bInitialized)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
}
|
|
}
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
INIT_EXT_HEADER(m_sHeader_Info.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_INFO, sizeof(m_sHeader_Info));
|
|
//m_sHeader_Info.sCommon.dwSize = sizeof(sP7Trace_Info);
|
|
//m_sHeader_Info.sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//m_sHeader_Info.sCommon.dwSubType = EP7TRACE_TYPE_INFO;
|
|
|
|
INIT_EXT_HEADER(m_sHeader_Data.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DATA, 0);
|
|
//m_sHeader_Data.sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//m_sHeader_Data.sCommon.dwSubType = EP7TRACE_TYPE_DATA;
|
|
|
|
if (i_pName)
|
|
{
|
|
PUStrCpy(m_sHeader_Info.pName, P7TRACE_NAME_LENGTH, i_pName);
|
|
}
|
|
else
|
|
{
|
|
PUStrCpy(m_sHeader_Info.pName, P7TRACE_NAME_LENGTH, TM("Unknown"));
|
|
}
|
|
|
|
if (m_sConf.qwTimestamp_Frequency)
|
|
{
|
|
m_sHeader_Info.qwTimer_Frequency = m_sConf.qwTimestamp_Frequency;
|
|
m_sHeader_Info.qwTimer_Value = m_sConf.pTimestamp_Callback(m_sConf.pContext);
|
|
}
|
|
else
|
|
{
|
|
m_sHeader_Info.qwTimer_Frequency = GetPerformanceFrequency();
|
|
m_sHeader_Info.qwTimer_Value = GetPerformanceCounter();
|
|
}
|
|
|
|
GetEpochTime(&m_sHeader_Info.dwTime_Hi, &m_sHeader_Info.dwTime_Lo);
|
|
|
|
m_sHeader_Info.qwFlags = P7TRACE_INFO_FLAG_EXTENTION | P7TRACE_INFO_FLAG_TIME_ZONE;
|
|
|
|
//Add main header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(m_sHeader_Info);
|
|
m_pChk_Curs->pData = &m_sHeader_Info;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
|
|
m_pChk_Curs ++;
|
|
|
|
//Add utc offset information
|
|
INIT_EXT_HEADER(m_sHeader_Utc.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_UTC_OFFS, sizeof(m_sHeader_Utc));
|
|
m_sHeader_Utc.iUtcOffsetSec = GetUtcOffsetSeconds();
|
|
|
|
//Add utc header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(m_sHeader_Utc);
|
|
m_pChk_Curs->pData = &m_sHeader_Utc;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
|
|
m_pChk_Curs ++;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// This code is dedicated to printing stack in case of crash, main idea is
|
|
// preallocate trace messages and all related memory for quick stack dump
|
|
// without allocation any new memory, but for the moment this functionality
|
|
// is frozen
|
|
// if (m_bInitialized)
|
|
// {
|
|
// tKeyType l_pKey[P7TRACE_KEY_LENGTH];
|
|
// l_pKey[0] = (tKeyType)FORMAT_FUNC_UNKNOWN;
|
|
// l_pKey[1] = (tKeyType)FORMAT_CRASH_MESSAGE;
|
|
//
|
|
// m_wDesc_Tree_ID ++;
|
|
// m_cDescU_Tree.Push(new CP7Trace_Desc(m_wDesc_Tree_ID,
|
|
// 0,
|
|
// 0,
|
|
// FORMAT_FILE_UNKNOWN,
|
|
// FORMAT_FUNC_UNKNOWN,
|
|
// FORMAT_CRASH_MESSAGE
|
|
// ),
|
|
// l_pKey
|
|
// );
|
|
//
|
|
// l_pKey[0] = (tKeyType)FORMAT_FUNC_UNKNOWN;
|
|
// l_pKey[1] = (tKeyType)FORMAT_STACK_MESSAGE;
|
|
//
|
|
// m_wDesc_Tree_ID ++;
|
|
// m_cDescU_Tree.Push(new CP7Trace_Desc(m_wDesc_Tree_ID,
|
|
// 0,
|
|
// 0,
|
|
// FORMAT_FILE_UNKNOWN,
|
|
// FORMAT_FUNC_UNKNOWN,
|
|
// FORMAT_STACK_MESSAGE
|
|
// ),
|
|
// l_pKey
|
|
// );
|
|
// }
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// tUINT32 l_dwCount = 0;
|
|
// const CStackTrace::sStack *l_pStack = m_cStack_Trace.Get_Stack(&l_dwCount, 0);
|
|
//
|
|
// *io_pCrash = FALSE;
|
|
//
|
|
// if (l_dwCount)
|
|
// {
|
|
// Trace(0,
|
|
// EP7TRACE_LEVEL_CRITICAL,
|
|
// 0,
|
|
// 0,
|
|
// FORMAT_FILE_UNKNOWN,
|
|
// FORMAT_FUNC_UNKNOWN,
|
|
// FORMAT_CRASH_MESSAGE
|
|
// );
|
|
//
|
|
// for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI ++)
|
|
// {
|
|
// Trace(0,
|
|
// EP7TRACE_LEVEL_INFO,
|
|
// 0,
|
|
// 0,
|
|
// FORMAT_FILE_UNKNOWN,
|
|
// FORMAT_FUNC_UNKNOWN,
|
|
// FORMAT_STACK_MESSAGE,
|
|
// l_dwI,
|
|
// l_pStack[l_dwI].pAddr,
|
|
// l_pStack[l_dwI].pName,
|
|
// l_pStack[l_dwI].dwLine
|
|
// );
|
|
// }
|
|
//
|
|
// }
|
|
|
|
|
|
if (m_bInitialized)
|
|
{
|
|
m_bIs_Channel = (ECLIENT_STATUS_OK == m_pClient->Register_Channel(this));
|
|
m_bInitialized = m_bIs_Channel;
|
|
if (!m_bInitialized)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_NoFreeChannels);
|
|
}
|
|
}
|
|
|
|
#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
if (m_bInitialized)
|
|
{
|
|
m_szVargs = 256;
|
|
m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs);
|
|
}
|
|
#else
|
|
if (m_bInitialized)
|
|
{
|
|
CP7Trace::sStack_Desc l_pDesc[6];
|
|
l_pDesc[0].uValue.dw32 = 0xDEADBEEFu;
|
|
l_pDesc[0].eType = CP7Trace::sStack_Desc::eTypeU32;
|
|
l_pDesc[0].bLast = FALSE;
|
|
|
|
l_pDesc[1].uValue.dw64 = 0x99ABCDEF12345678ull;
|
|
l_pDesc[1].eType = CP7Trace::sStack_Desc::eTypeU64;
|
|
l_pDesc[1].bLast = FALSE;
|
|
|
|
l_pDesc[2].uValue.dw32 = 0xABBADEFEu;
|
|
l_pDesc[2].eType = CP7Trace::sStack_Desc::eTypeU32;
|
|
l_pDesc[2].bLast = FALSE;
|
|
|
|
l_pDesc[3].uValue.dw32 = 0x98765432u;
|
|
l_pDesc[3].eType = CP7Trace::sStack_Desc::eTypeU32;
|
|
l_pDesc[3].bLast = FALSE;
|
|
|
|
l_pDesc[4].uValue.db64 = (tDOUBLE)362764.9;
|
|
l_pDesc[4].eType = CP7Trace::sStack_Desc::eTypeD64;
|
|
l_pDesc[4].bLast = FALSE;
|
|
|
|
l_pDesc[5].uValue.dw64 = 0x791A90204E0b4C6Dull;
|
|
l_pDesc[5].eType = CP7Trace::sStack_Desc::eTypeU64;
|
|
l_pDesc[5].bLast = TRUE;
|
|
|
|
if (!Is_VarArgs(l_pDesc,
|
|
l_pDesc[0].uValue.dw32,
|
|
l_pDesc[1].uValue.dw64,
|
|
l_pDesc[2].uValue.dw32,
|
|
l_pDesc[3].uValue.dw32,
|
|
l_pDesc[4].uValue.db64,
|
|
l_pDesc[5].uValue.dw64
|
|
)
|
|
)
|
|
{
|
|
printf("ERROR: P7.Trace detects that current architecture/compiler\n");
|
|
printf(" doesn't support location of variadic arguments on stack\n");
|
|
printf(" to make library works properly please activate macro\n");
|
|
printf(" \"P7TRACE_NO_VA_ARG_OPTIMIZATION\" in file \"P7_Trace.h\"\n");
|
|
printf(" Sorry for inconvenience and have a nice day!\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_bActive = m_bInitialized;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// ~CP7Trace
|
|
CP7Trace::~CP7Trace()
|
|
{
|
|
LOCK_ENTER(m_sCS);
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
if (m_hShared)
|
|
{
|
|
CShared::Close(m_hShared);
|
|
m_hShared = NULL;
|
|
}
|
|
|
|
if (m_bIs_Channel)
|
|
{
|
|
Flush();
|
|
|
|
m_pClient->Unregister_Channel(m_dwChannel_ID);
|
|
}
|
|
|
|
//memory used from pool, not necessary to return
|
|
memset(m_pDesc_Array, 0, sizeof(m_pDesc_Array));
|
|
|
|
m_cThreadsR.Clear(TRUE);
|
|
m_cThreadsS.Clear(TRUE);
|
|
m_cModules.Clear(TRUE);
|
|
|
|
m_cDescU_Tree.Clear();
|
|
m_cDescM_Tree.Clear();
|
|
|
|
if (m_pClient)
|
|
{
|
|
m_pClient->Release();
|
|
m_pClient = NULL;
|
|
}
|
|
|
|
if (m_pChk_Head)
|
|
{
|
|
free(m_pChk_Head);
|
|
m_pChk_Head = NULL;
|
|
}
|
|
|
|
m_pChk_Curs = NULL;
|
|
m_dwChk_Count = 0;
|
|
|
|
m_pVargs = NULL;
|
|
m_szVargs = 0;
|
|
|
|
LOCK_DESTROY(m_sCS);
|
|
}// ~CP7Trace
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Is_Initialized
|
|
tBOOL CP7Trace::Is_Initialized()
|
|
{
|
|
return m_bInitialized;
|
|
}// Is_Initialized
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// On_Init
|
|
void CP7Trace::On_Init(sP7C_Channel_Info *i_pInfo)
|
|
{
|
|
if (i_pInfo)
|
|
{
|
|
m_dwChannel_ID = i_pInfo->dwID;
|
|
}
|
|
}// On_Init
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// On_Receive
|
|
void CP7Trace::On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian)
|
|
{
|
|
UNUSED_ARG(i_dwChannel);
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
if ( (i_pBuffer)
|
|
&& (i_dwSize >= sizeof(sP7Ext_Header))
|
|
)
|
|
{
|
|
sP7Ext_Raw l_sHeader = *(sP7Ext_Raw*)i_pBuffer;
|
|
|
|
if (EP7USER_TYPE_TRACE == GET_EXT_HEADER_TYPE(l_sHeader))
|
|
{
|
|
if (EP7TRACE_TYPE_VERB == GET_EXT_HEADER_SUBTYPE(l_sHeader))
|
|
{
|
|
sP7Trace_Module *l_pModule = NULL;
|
|
|
|
if (i_bBigEndian)
|
|
{
|
|
((sP7Trace_Verb*)i_pBuffer)->wModuleID = htons(((sP7Trace_Verb*)i_pBuffer)->wModuleID);
|
|
((sP7Trace_Verb*)i_pBuffer)->eVerbosity = (eP7Trace_Level)htonl(((sP7Trace_Verb*)i_pBuffer)->eVerbosity);
|
|
}
|
|
|
|
//if it is old protocol and field wModuleID isn't included into command
|
|
//or if module ID is 0
|
|
if ( (i_dwSize < sizeof(sP7Trace_Verb))
|
|
|| (!((sP7Trace_Verb*)i_pBuffer)->wModuleID)
|
|
)
|
|
{
|
|
m_eVerbosity = ((sP7Trace_Verb*)i_pBuffer)->eVerbosity;
|
|
}
|
|
else //set module verbosity
|
|
{
|
|
tUINT16 l_wModuleID = ((sP7Trace_Verb*)i_pBuffer)->wModuleID - 1;
|
|
pAList_Cell l_pEl = NULL;
|
|
sModules *l_pModules = NULL;
|
|
|
|
l_pEl = NULL;
|
|
while ((l_pEl = m_cModules.Get_Next(l_pEl)))
|
|
{
|
|
l_pModules = m_cModules.Get_Data(l_pEl);
|
|
if (l_pModules->dwUsed > l_wModuleID)
|
|
{
|
|
l_pModules->pData[l_wModuleID].eVerbosity = ((sP7Trace_Verb*)i_pBuffer)->eVerbosity;
|
|
l_pModule = &l_pModules->pData[l_wModuleID];
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
l_wModuleID -= l_pModules->dwUsed;
|
|
}
|
|
}//while (l_pEl = m_cThreadsR.Get_Next(l_pEl))
|
|
}
|
|
|
|
if (m_sConf.pVerbosity_Callback)
|
|
{
|
|
m_sConf.pVerbosity_Callback(m_sConf.pContext, l_pModule, ((sP7Trace_Verb*)i_pBuffer)->eVerbosity);
|
|
}
|
|
}
|
|
else if (EP7TRACE_TYPE_DELETE == GET_EXT_HEADER_SUBTYPE(l_sHeader))
|
|
{
|
|
Flush();
|
|
m_bActive = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOCK_EXIT(m_sCS);
|
|
}// On_Receive
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// On_Status
|
|
void CP7Trace::On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus)
|
|
{
|
|
UNUSED_ARG(i_dwChannel);
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
if (i_pStatus)
|
|
{
|
|
//if connection was established - sent threads info ...
|
|
if ( (i_pStatus->dwResets != m_sStatus.dwResets)
|
|
&& (i_pStatus->bConnected)
|
|
)
|
|
{
|
|
pAList_Cell l_pEl = NULL;
|
|
sThreadsR *l_pThreadsR = NULL;
|
|
sThreadsS *l_pThreadsS = NULL;
|
|
sModules *l_pModules = NULL;
|
|
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
|
|
//Add main header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(m_sHeader_Info);
|
|
m_pChk_Curs->pData = &m_sHeader_Info;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
|
|
m_pChk_Curs ++;
|
|
|
|
//Add utc offset header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(m_sHeader_Utc);
|
|
m_pChk_Curs->pData = &m_sHeader_Utc;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
|
|
m_pChk_Curs ++;
|
|
|
|
//add active threads desc. to delivery chunks list
|
|
l_pEl = NULL;
|
|
while ((l_pEl = m_cThreadsR.Get_Next(l_pEl)))
|
|
{
|
|
l_pThreadsR = m_cThreadsR.Get_Data(l_pEl);
|
|
if (l_pThreadsR->dwUsed)
|
|
{
|
|
m_pChk_Curs->pData = l_pThreadsR->pData;
|
|
m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Start) * l_pThreadsR->dwUsed;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
}
|
|
}//while (l_pEl = m_cThreadsR.Get_Next(l_pEl))
|
|
|
|
//add stopped threads desc. to delivery chunks list
|
|
l_pEl = NULL;
|
|
while ((l_pEl = m_cThreadsS.Get_Next(l_pEl)))
|
|
{
|
|
l_pThreadsS = m_cThreadsS.Get_Data(l_pEl);
|
|
if (l_pThreadsR->dwUsed)
|
|
{
|
|
m_pChk_Curs->pData = l_pThreadsS->pData;
|
|
m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Stop) * l_pThreadsS->dwUsed;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
}
|
|
}//while (l_pEl = m_cThreadsR.Get_Next(l_pEl))
|
|
|
|
//add modules descriptions to chunks list
|
|
l_pEl = NULL;
|
|
while ((l_pEl = m_cModules.Get_Next(l_pEl)))
|
|
{
|
|
l_pModules = m_cModules.Get_Data(l_pEl);
|
|
if (l_pModules->dwUsed)
|
|
{
|
|
m_pChk_Curs->pData = l_pModules->pData;
|
|
m_pChk_Curs->dwSize = sizeof(sP7Trace_Module) * l_pModules->dwUsed;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
}
|
|
}//while (l_pEl = m_cThreadsR.Get_Next(l_pEl))
|
|
|
|
}//(i_pStatus->dwResets != m_sStatus.dwResets) ...
|
|
|
|
m_sStatus = *i_pStatus;
|
|
|
|
if (m_sConf.pConnect_Callback)
|
|
{
|
|
m_sConf.pConnect_Callback(m_sConf.pContext, m_sStatus.bConnected);
|
|
}
|
|
}
|
|
LOCK_EXIT(m_sCS);
|
|
}// On_Status
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// On_Flush - external call
|
|
void CP7Trace::On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash)
|
|
{
|
|
UNUSED_ARG(i_dwChannel);
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
if ( (io_pCrash)
|
|
&& (TRUE == *io_pCrash)
|
|
&& (m_bActive)
|
|
)
|
|
{
|
|
//nothing special for crash event
|
|
}
|
|
|
|
Flush();
|
|
|
|
LOCK_EXIT(m_sCS);
|
|
}// On_Flush
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Register_Thread
|
|
tBOOL CP7Trace::Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId)
|
|
{
|
|
tBOOL l_bExtended = FALSE;
|
|
tBOOL l_bReturn = TRUE;
|
|
|
|
if (NULL == i_pName)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
sP7Trace_Thread_Start *l_pThread = NULL;
|
|
sThreadsR *l_pThreads = m_cThreadsR.Get_Data(m_cThreadsR.Get_Last());
|
|
sP7C_Data_Chunk *l_pChunk = m_pChk_Head;
|
|
|
|
if ( (NULL == l_pThreads)
|
|
|| (l_pThreads->dwUsed >= l_pThreads->dwCount)
|
|
)
|
|
{
|
|
if ((m_cThreadsR.Count() * P7TRACE_THREADS_POOL_SIZE) < P7TRACE_THREADS_MAX_SIZE)
|
|
{
|
|
l_pThreads = new sThreadsR(P7TRACE_THREADS_POOL_SIZE);
|
|
m_cThreadsR.Add_After(m_cThreadsR.Get_Last(), l_pThreads);
|
|
}
|
|
else
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pThread = &l_pThreads->pData[l_pThreads->dwUsed];
|
|
l_pThreads->dwUsed ++;
|
|
|
|
INIT_EXT_HEADER(l_pThread->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_THREAD_START, sizeof(sP7Trace_Thread_Start));
|
|
//l_pThread->sCommon.dwSize = sizeof(sP7Trace_Thread_Start);
|
|
//l_pThread->sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_pThread->sCommon.dwSubType = EP7TRACE_TYPE_THREAD_START;
|
|
|
|
l_pThread->dwThreadID = (!i_dwThreadId) ? CProc::Get_Thread_Id() : i_dwThreadId;
|
|
|
|
if (! m_sConf.pTimestamp_Callback )
|
|
{
|
|
l_pThread->qwTimer = GetPerformanceCounter();
|
|
}
|
|
else
|
|
{
|
|
l_pThread->qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext);
|
|
}
|
|
|
|
#ifdef UTF8_ENCODING
|
|
PStrCpy(l_pThread->pName, P7TRACE_THREAD_NAME_LENGTH, i_pName);
|
|
#else
|
|
Convert_UTF16_To_UTF8((const tWCHAR*)i_pName,
|
|
l_pThread->pName,
|
|
P7TRACE_THREAD_NAME_LENGTH
|
|
);
|
|
#endif
|
|
|
|
//look for existing chunks which can be updated
|
|
while (l_pChunk < m_pChk_Curs)
|
|
{
|
|
//if new thread address is beginning of existing chunk pointer
|
|
if (((tUINT8*)l_pThread + sizeof(sP7Trace_Thread_Start)) == l_pChunk->pData)
|
|
{
|
|
l_pChunk->pData = l_pThread;
|
|
l_pChunk->dwSize += sizeof(sP7Trace_Thread_Start);
|
|
m_dwChk_Size += sizeof(sP7Trace_Thread_Start);
|
|
l_bExtended = TRUE;
|
|
break;
|
|
}
|
|
//if new thread address is continuation of existing chunk pointer
|
|
else if (((tUINT8*)l_pChunk->pData + l_pChunk->dwSize) == (tUINT8*)l_pThread)
|
|
{
|
|
l_pChunk->dwSize += sizeof(sP7Trace_Thread_Start);
|
|
m_dwChk_Size += sizeof(sP7Trace_Thread_Start);
|
|
l_bExtended = TRUE;
|
|
break;
|
|
}
|
|
|
|
l_pChunk ++;
|
|
}
|
|
|
|
//if chunk was not extended ...
|
|
if (FALSE == l_bExtended)
|
|
{
|
|
//Add thread header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Start);
|
|
m_pChk_Curs->pData = l_pThread;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
}
|
|
|
|
if ( (m_sStatus.bConnected)
|
|
&& (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(m_pChk_Curs - m_pChk_Head),
|
|
m_dwChk_Size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
}//Register_Thread
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Unregister_Thread
|
|
tBOOL CP7Trace::Unregister_Thread(tUINT32 i_dwThreadId)
|
|
{
|
|
tBOOL l_bReturn = FALSE;
|
|
sThreadsR *l_pStarted = NULL;
|
|
sThreadsS *l_pStopped = NULL;
|
|
sP7Trace_Thread_Stop *l_pStop = NULL;
|
|
pAList_Cell l_pEl = NULL;
|
|
|
|
if (!i_dwThreadId)
|
|
{
|
|
i_dwThreadId = CProc::Get_Thread_Id();
|
|
}
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
while ((l_pEl = m_cThreadsR.Get_Next(l_pEl)))
|
|
{
|
|
l_pStarted = m_cThreadsR.Get_Data(l_pEl);
|
|
for (tUINT32 l_dwI = 0; l_dwI < l_pStarted->dwUsed; l_dwI++)
|
|
{
|
|
if (i_dwThreadId == l_pStarted->pData[l_dwI].dwThreadID)
|
|
{
|
|
l_bReturn = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//such thread isn't registered !
|
|
if (!l_bReturn)
|
|
{
|
|
goto l_lblExit;
|
|
}
|
|
|
|
//save current Stop command in queue
|
|
l_pStopped = m_cThreadsS.Get_Data(m_cThreadsS.Get_Last());
|
|
|
|
if ( (NULL == l_pStopped)
|
|
|| (l_pStopped->dwUsed >= l_pStopped->dwCount)
|
|
)
|
|
{
|
|
if ((m_cThreadsS.Count() * P7TRACE_THREADS_POOL_SIZE) < P7TRACE_THREADS_MAX_SIZE)
|
|
{
|
|
l_pStopped = new sThreadsS(P7TRACE_THREADS_POOL_SIZE);
|
|
m_cThreadsS.Add_After(m_cThreadsS.Get_Last(), l_pStopped);
|
|
}
|
|
else
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pStop = &l_pStopped->pData[l_pStopped->dwUsed];
|
|
l_pStopped->dwUsed ++;
|
|
|
|
INIT_EXT_HEADER(l_pStop->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_THREAD_STOP, sizeof(sP7Trace_Thread_Stop));
|
|
//l_pStop->sCommon.dwSize = sizeof(sP7Trace_Thread_Stop);
|
|
//l_pStop->sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_pStop->sCommon.dwSubType = EP7TRACE_TYPE_THREAD_STOP;
|
|
|
|
l_pStop->dwThreadID = i_dwThreadId;
|
|
if (! m_sConf.pTimestamp_Callback )
|
|
{
|
|
l_pStop->qwTimer = GetPerformanceCounter();
|
|
}
|
|
else
|
|
{
|
|
l_pStop->qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext);
|
|
}
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
|
|
m_pChk_Curs->pData = l_pStop;
|
|
m_pChk_Curs->dwSize = GET_EXT_HEADER_SIZE(l_pStop->sCommonRaw);
|
|
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if ( (m_sStatus.bConnected)
|
|
&& (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(m_pChk_Curs - m_pChk_Head),
|
|
m_dwChk_Size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
|
|
//delete all closed threads and related active threads
|
|
while ((l_pEl = m_cThreadsS.Get_Last()))
|
|
{
|
|
l_pStopped = m_cThreadsS.Get_Data(l_pEl);
|
|
|
|
for (tUINT32 l_dwI = 0; l_dwI < l_pStopped->dwUsed; l_dwI++)
|
|
{
|
|
sP7Trace_Thread_Start *l_pCurrent = NULL;
|
|
sP7Trace_Thread_Start *l_pLast = NULL;
|
|
pAList_Cell l_pElR = NULL;
|
|
|
|
//looking through active threads to find thread by ID
|
|
while ((l_pElR = m_cThreadsR.Get_Next(l_pElR)))
|
|
{
|
|
l_pStarted = m_cThreadsR.Get_Data(l_pElR);
|
|
|
|
for (tUINT32 l_dwJ = 0; l_dwJ < l_pStarted->dwUsed; l_dwJ++)
|
|
{
|
|
if (l_pStopped->pData[l_dwI].dwThreadID == l_pStarted->pData[l_dwJ].dwThreadID)
|
|
{
|
|
l_pCurrent = &l_pStarted->pData[l_dwJ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (l_pCurrent)
|
|
{
|
|
sThreadsR *l_pLastR = m_cThreadsR.Get_Data(m_cThreadsR.Get_Last());
|
|
|
|
if ( (l_pLastR)
|
|
&& (l_pLastR->dwUsed)
|
|
)
|
|
{
|
|
l_pLast = &l_pLastR->pData[l_pLastR->dwUsed - 1];
|
|
|
|
if (l_pLast != l_pCurrent)
|
|
{
|
|
memcpy(l_pCurrent, l_pLast, sizeof(sP7Trace_Thread_Start));
|
|
}
|
|
|
|
l_pLastR->dwUsed --;
|
|
|
|
if ( (0 == l_pLastR->dwUsed)
|
|
&& (1 < m_cThreadsR.Count())
|
|
)
|
|
{
|
|
m_cThreadsR.Del(m_cThreadsR.Get_Last(), TRUE);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}//while (l_pElR = m_cThreadsR.Get_Next(l_pElR))
|
|
}//for (tUINT32 l_dwI = 0; l_dwI < l_pStopped->dwUsed; l_dwI++)
|
|
|
|
m_cThreadsS.Del(l_pEl, TRUE);
|
|
}//while (l_pEl = m_cThreadsS.Get_Last())
|
|
} //m_pClient->Sent(...)
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
}// Unregister_Thread
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Register_Module
|
|
tBOOL CP7Trace::Register_Module(const tXCHAR *i_pName, IP7_Trace::hModule *o_hModule)
|
|
{
|
|
if ( (NULL == i_pName)
|
|
|| (NULL == o_hModule)
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
tBOOL l_bReturn = TRUE;
|
|
sP7Trace_Module *l_pModule = NULL;
|
|
sModules *l_pModules = m_cModules.Get_Data(m_cModules.Get_Last());
|
|
sP7C_Data_Chunk *l_pChunk = m_pChk_Head;
|
|
tBOOL l_bExtended = FALSE;
|
|
sModuleMap *l_pMap = NULL;
|
|
|
|
//looking through existing modules -if found - return it
|
|
l_pMap = m_cModules_Map.Find(i_pName);
|
|
if (l_pMap)
|
|
{
|
|
*o_hModule = l_pMap->pModule;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
//module isn't exists - create new one
|
|
if ( (NULL == l_pModules)
|
|
|| (l_pModules->dwUsed >= l_pModules->dwCount)
|
|
)
|
|
{
|
|
if ((m_cModules.Count() * P7TRACE_MODULES_POOL_SIZE) < P7TRACE_MODULES_MAX_SIZE)
|
|
{
|
|
l_pModules = new sModules(P7TRACE_MODULES_POOL_SIZE);
|
|
m_cModules.Add_After(m_cModules.Get_Last(), l_pModules);
|
|
}
|
|
else
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pModule = &l_pModules->pData[l_pModules->dwUsed];
|
|
l_pModules->dwUsed ++;
|
|
|
|
INIT_EXT_HEADER(l_pModule->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_MODULE, sizeof(sP7Trace_Module));
|
|
//l_pModule->sCommon.dwSize = sizeof(sP7Trace_Module);
|
|
//l_pModule->sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_pModule->sCommon.dwSubType = EP7TRACE_TYPE_MODULE;
|
|
|
|
l_pModule->eVerbosity = m_eVerbosity;
|
|
l_pModule->wModuleID = m_wLast_ModuleID++;
|
|
|
|
#ifdef UTF8_ENCODING
|
|
PStrCpy(l_pModule->pName, P7TRACE_THREAD_NAME_LENGTH, i_pName);
|
|
#else
|
|
Convert_UTF16_To_UTF8((const tWCHAR*)i_pName,
|
|
l_pModule->pName,
|
|
P7TRACE_MODULE_NAME_LENGTH
|
|
);
|
|
#endif
|
|
|
|
//add module to tree
|
|
l_pMap = new sModuleMap(i_pName, l_pModule);
|
|
if (!m_cModules_Map.Push(l_pMap, i_pName))
|
|
{
|
|
delete l_pMap;
|
|
l_pMap = NULL;
|
|
}
|
|
|
|
//look for existing chunks which can be updated
|
|
while (l_pChunk < m_pChk_Curs)
|
|
{
|
|
//if new thread address is beginning of existing chunk pointer
|
|
if (((tUINT8*)l_pModule + sizeof(sP7Trace_Module)) == l_pChunk->pData)
|
|
{
|
|
l_pChunk->pData = l_pModule;
|
|
l_pChunk->dwSize += sizeof(sP7Trace_Module);
|
|
m_dwChk_Size += sizeof(sP7Trace_Module);
|
|
l_bExtended = TRUE;
|
|
break;
|
|
}
|
|
//if new thread address is continuation of existing chunk pointer
|
|
else if (((tUINT8*)l_pChunk->pData + l_pChunk->dwSize) == (tUINT8*)l_pModule)
|
|
{
|
|
l_pChunk->dwSize += sizeof(sP7Trace_Module);
|
|
m_dwChk_Size += sizeof(sP7Trace_Module);
|
|
l_bExtended = TRUE;
|
|
break;
|
|
}
|
|
|
|
l_pChunk ++;
|
|
}
|
|
|
|
//if chunk was not extended ...
|
|
if (FALSE == l_bExtended)
|
|
{
|
|
//Add thread header to delivery chunks list
|
|
m_pChk_Curs->dwSize = sizeof(sP7Trace_Module);
|
|
m_pChk_Curs->pData = l_pModule;
|
|
m_dwChk_Size += m_pChk_Curs->dwSize;
|
|
m_pChk_Curs ++;
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
}
|
|
|
|
//deliver
|
|
if ( (m_sStatus.bConnected)
|
|
&& (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(m_pChk_Curs - m_pChk_Head),
|
|
m_dwChk_Size
|
|
)
|
|
)
|
|
)
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
|
|
*o_hModule = l_pModule;
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
}// Register_Module
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Set_Verbosity
|
|
void CP7Trace::Set_Verbosity(IP7_Trace::hModule i_hModule, eP7Trace_Level i_eVerbosity)
|
|
{
|
|
LOCK_ENTER(m_sCS);
|
|
sP7C_Data_Chunk *l_pChunk = NULL;
|
|
tUINT32 l_dwSize = m_dwChk_Size;
|
|
sP7Trace_Verb l_sCmd;
|
|
|
|
if (i_hModule)
|
|
{
|
|
((sP7Trace_Module*)i_hModule)->eVerbosity = i_eVerbosity;
|
|
}
|
|
else
|
|
{
|
|
m_eVerbosity = i_eVerbosity;
|
|
}
|
|
|
|
if (m_pChk_Curs >= m_pChk_Tail)
|
|
{
|
|
if (!Inc_Chunks(64))
|
|
{
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pChunk = m_pChk_Curs;
|
|
|
|
|
|
INIT_EXT_HEADER(l_sCmd.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_VERB, sizeof(sP7Trace_Verb));
|
|
//l_sCmd.sCommon.dwSize = sizeof(sP7Trace_Verb);
|
|
//l_sCmd.sCommon.dwType = EP7USER_TYPE_TRACE;
|
|
//l_sCmd.sCommon.dwSubType = EP7TRACE_TYPE_VERB;
|
|
|
|
l_sCmd.eVerbosity = i_eVerbosity;
|
|
l_sCmd.wModuleID = (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0;
|
|
|
|
l_pChunk->pData = &l_sCmd;
|
|
l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_sCmd.sCommonRaw);
|
|
l_dwSize += GET_EXT_HEADER_SIZE(l_sCmd.sCommonRaw);
|
|
|
|
l_pChunk++;
|
|
|
|
//deliver
|
|
if ( (m_sStatus.bConnected)
|
|
&& (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(l_pChunk - m_pChk_Head),
|
|
l_dwSize
|
|
)
|
|
)
|
|
)
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
}// Set_Verbosity
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Get_Verbosity
|
|
eP7Trace_Level CP7Trace::Get_Verbosity(IP7_Trace::hModule i_hModule)
|
|
{
|
|
eP7Trace_Level l_eReturn = EP7TRACE_LEVEL_COUNT;
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
if (i_hModule)
|
|
{
|
|
l_eReturn = ((sP7Trace_Module*)i_hModule)->eVerbosity;
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = m_eVerbosity;
|
|
}
|
|
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_eReturn;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Trace
|
|
tBOOL CP7Trace::Trace(tUINT16 i_wTrace_ID,
|
|
eP7Trace_Level i_eLevel,
|
|
IP7_Trace::hModule i_hModule,
|
|
tUINT16 i_wLine,
|
|
const char *i_pFile,
|
|
const char *i_pFunction,
|
|
const tXCHAR *i_pFormat,
|
|
...
|
|
)
|
|
{
|
|
#if !defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
return Trace_Raw(i_wTrace_ID,
|
|
i_eLevel,
|
|
i_hModule,
|
|
i_wLine,
|
|
i_pFile,
|
|
i_pFunction,
|
|
(tKeyType*)&i_pFunction,
|
|
&i_pFormat,
|
|
NULL
|
|
);
|
|
#else
|
|
va_list l_pVl;
|
|
va_start(l_pVl, i_pFormat);
|
|
tKeyType l_pKey[2] = {(tKeyType)i_pFunction, (tKeyType)i_pFormat};
|
|
tBOOL l_bRet = Trace_Raw(i_wTrace_ID,
|
|
i_eLevel,
|
|
i_hModule,
|
|
i_wLine,
|
|
i_pFile,
|
|
i_pFunction,
|
|
l_pKey,
|
|
&i_pFormat,
|
|
&l_pVl
|
|
);
|
|
va_end(l_pVl);
|
|
return l_bRet;
|
|
#endif
|
|
}// Trace
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Share
|
|
tBOOL CP7Trace::Share(const tXCHAR *i_pName)
|
|
{
|
|
tBOOL l_bReturn = FALSE;
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
if (NULL == m_hShared)
|
|
{
|
|
tUINT32 l_dwLen1 = PStrLen(TRACE_SHARED_PREFIX);
|
|
tUINT32 l_dwLen2 = PStrLen(i_pName);
|
|
tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16));
|
|
CShared::hSem l_hSem = SHARED_SEM_NULL;
|
|
|
|
if (l_pName)
|
|
{
|
|
sObjShared l_stShared = {};
|
|
tUINT32 l_uTimeHi = 0;
|
|
tUINT32 l_uTimeLo = 0;
|
|
tBOOL l_bCreate = TRUE;
|
|
|
|
CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo);
|
|
|
|
PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TRACE_SHARED_PREFIX);
|
|
PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName);
|
|
|
|
//JOURNAL_WARNING(m_pLog, TM("Shared memory {%s} registration error"), l_pName);
|
|
if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250))
|
|
{
|
|
l_bCreate = FALSE; //it is already existing
|
|
|
|
if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)))
|
|
{
|
|
if ( (l_stShared.uProcTimeHi != l_uTimeHi)
|
|
|| (l_stShared.uProcTimeLo != l_uTimeLo)
|
|
)
|
|
{
|
|
//JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp error, prev. session crashed or forget to release P7 objects?"));
|
|
CShared::UnLink(l_pName);
|
|
l_bCreate = TRUE;
|
|
}
|
|
}
|
|
|
|
CShared::UnLock(l_hSem);
|
|
}
|
|
|
|
if (l_bCreate)
|
|
{
|
|
CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo);
|
|
l_stShared.pPointer = static_cast<IP7_Trace*>(this);
|
|
l_stShared.uProcTimeHi = l_uTimeHi;
|
|
l_stShared.uProcTimeLo = l_uTimeLo;
|
|
|
|
l_bReturn = CShared::Create(&m_hShared, l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared));
|
|
}
|
|
|
|
free(l_pName);
|
|
l_pName = NULL;
|
|
}
|
|
}
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
}// Share
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// On_Flush - internal call
|
|
void CP7Trace::Flush()
|
|
{
|
|
if (FALSE == m_bActive)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_bActive = FALSE;
|
|
|
|
sP7C_Data_Chunk *l_pChunk = m_pChk_Curs;
|
|
tUINT32 l_dwSize = m_dwChk_Size;
|
|
sP7Ext_Raw l_sHeader;
|
|
|
|
INIT_EXT_HEADER(l_sHeader, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_CLOSE, sizeof(sP7Ext_Raw));
|
|
|
|
l_pChunk->pData = &l_sHeader;
|
|
l_pChunk->dwSize = sizeof(sP7Ext_Raw);
|
|
l_dwSize += sizeof(sP7Ext_Raw);
|
|
|
|
l_pChunk++;
|
|
|
|
if (l_pChunk >= m_pChk_Tail)
|
|
{
|
|
Inc_Chunks(64);
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(l_pChunk - m_pChk_Head),
|
|
l_dwSize
|
|
)
|
|
)
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
}// On_Flush
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Trace_Embedded
|
|
tBOOL CP7Trace::Trace_Embedded(tUINT16 i_wTrace_ID,
|
|
eP7Trace_Level i_eLevel,
|
|
IP7_Trace::hModule i_hModule,
|
|
tUINT16 i_wLine,
|
|
const char *i_pFile,
|
|
const char *i_pFunction,
|
|
const tXCHAR **i_ppFormat
|
|
)
|
|
{
|
|
#if !defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
tKeyType l_pKey[P7TRACE_KEY_LENGTH] = {(tKeyType)i_pFunction, (tKeyType)*i_ppFormat};
|
|
|
|
return Trace_Raw(i_wTrace_ID,
|
|
i_eLevel,
|
|
i_hModule,
|
|
i_wLine,
|
|
i_pFile,
|
|
i_pFunction,
|
|
l_pKey,
|
|
i_ppFormat,
|
|
NULL
|
|
);
|
|
#else
|
|
UNUSED_ARG(i_wTrace_ID);
|
|
UNUSED_ARG(i_eLevel);
|
|
UNUSED_ARG(i_hModule);
|
|
UNUSED_ARG(i_wLine);
|
|
UNUSED_ARG(i_pFile);
|
|
UNUSED_ARG(i_pFunction);
|
|
UNUSED_ARG(i_ppFormat);
|
|
|
|
static tBOOL g_bVaArgError = FALSE;
|
|
if (!g_bVaArgError)
|
|
{
|
|
g_bVaArgError = TRUE;
|
|
printf("P7 TRACE ERROR: Trace_Embedded function is obsolete!\n");
|
|
}
|
|
return FALSE;
|
|
#endif
|
|
}// Trace_Embedded
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Trace_Embedded
|
|
tBOOL CP7Trace::Trace_Embedded(tUINT16 i_wTrace_ID,
|
|
eP7Trace_Level i_eLevel,
|
|
IP7_Trace::hModule i_hModule,
|
|
tUINT16 i_wLine,
|
|
const char *i_pFile,
|
|
const char *i_pFunction,
|
|
const tXCHAR **i_ppFormat,
|
|
va_list *i_pVa_List
|
|
)
|
|
{
|
|
tKeyType l_pKey[P7TRACE_KEY_LENGTH] = {(tKeyType)i_pFunction, (tKeyType)*i_ppFormat};
|
|
|
|
return Trace_Raw(i_wTrace_ID,
|
|
i_eLevel,
|
|
i_hModule,
|
|
i_wLine,
|
|
i_pFile,
|
|
i_pFunction,
|
|
l_pKey,
|
|
i_ppFormat,
|
|
i_pVa_List
|
|
);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Trace_Managed
|
|
tBOOL CP7Trace::Trace_Managed(tUINT16 i_wTrace_ID,
|
|
eP7Trace_Level i_eLevel,
|
|
IP7_Trace::hModule i_hModule,
|
|
tUINT16 i_wLine,
|
|
const tXCHAR *i_pFile,
|
|
const tXCHAR *i_pFunction,
|
|
const tXCHAR *i_pMessage
|
|
)
|
|
{
|
|
tBOOL l_bReturn = TRUE;
|
|
tUINT32 l_dwSize = 0;
|
|
CP7Trace_Desc *l_pDesc = NULL;
|
|
tBOOL l_bDesc = FALSE;
|
|
size_t l_szTrace = 0;
|
|
sP7C_Data_Chunk *l_pChunk; //we do not initialize it here, we do it later
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
m_dwSequence ++;
|
|
|
|
if ( (i_eLevel < m_eVerbosity)
|
|
|| (FALSE == m_bActive)
|
|
|| (FALSE == m_sStatus.bConnected)
|
|
|| ( (i_hModule)
|
|
&& (i_eLevel < ((sP7Trace_Module*)i_hModule)->eVerbosity)
|
|
)
|
|
)
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//if user specify direct Trace ID
|
|
if ( (1 <= i_wTrace_ID)
|
|
&& (P7_TRACE_DESC_HARDCODED_COUNT > i_wTrace_ID)
|
|
)
|
|
{
|
|
l_pDesc = m_pDesc_Array[i_wTrace_ID];
|
|
if (NULL == l_pDesc)
|
|
{
|
|
l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc)))
|
|
CP7Trace_Desc(m_cMemory,
|
|
i_wTrace_ID,
|
|
i_wLine,
|
|
(i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0,
|
|
i_pFile,
|
|
i_pFunction,
|
|
(tKeyType*)NULL
|
|
);
|
|
m_pDesc_Array[i_wTrace_ID] = l_pDesc;
|
|
}
|
|
}
|
|
else //if we should use map to find it
|
|
{
|
|
tKeyType l_pKeys[P7TRACE_KEY_LENGTH] = {0ul, 2166136261ul};
|
|
const tXCHAR *l_pFile = i_pFile;
|
|
|
|
//Here is RedBlackTree keys are calculated, key is consisting of 2 parts
|
|
//l_pKeys[0] = [16 bits: i_pFile string length][16 bits: line number]
|
|
//l_pKeys[1] = FNV-1a 32bits hash of i_pFile
|
|
//Hash description: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
|
|
//Hash parameters investigation (collisions, randomnessification)
|
|
//http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed
|
|
//Collisions:
|
|
// - Is collisions are possible ? Yes, FNV-1a produce 4 coll. on list of
|
|
// 216,553 English words. But count of uniq. trace ID is limited to
|
|
// 64k, and in addition to hash I'm using second key containing string
|
|
// length and source code line number.
|
|
// - If collision happens and even calculated key is not unique - is it
|
|
// dangerous ? No, even in this hypothetical situation the maximal
|
|
// risk is displaying wrong [i_wLine, i_pFile, i_pFunction] values on
|
|
// Baical side
|
|
// - May we prevent not unique key issue ? Yes, but it will require in
|
|
// addition checking all 3 parameters [i_wLine, i_pFile, i_pFunction]
|
|
// after key searching in tree, this is heavy string operation for
|
|
// every trace message
|
|
// Conclusion:
|
|
// - real risk of hash collision is low on 64k unique traces
|
|
// - risk of calculating not unique key is much lower than collision due
|
|
// to different parameters combination in addition to hash
|
|
// - data damage in case of not unique key isn't significant, main
|
|
// trace message and all its parameters will be delivered properly,
|
|
// except [i_wLine, i_pFile, i_pFunction].
|
|
// So additional protection wasn't implemented
|
|
while (*l_pFile)
|
|
{
|
|
l_pKeys[0] ++; //string length
|
|
l_pKeys[1] = (tKeyType)(l_pKeys[1] ^ (tXCHAR)*l_pFile) * 16777619ul;
|
|
l_pFile++;
|
|
}
|
|
|
|
l_pKeys[0] = (l_pKeys[0] << 16) + (tKeyType)i_wLine;
|
|
|
|
l_pDesc = m_cDescM_Tree.Find(l_pKeys);
|
|
if ( (NULL == l_pDesc)
|
|
&& (0xFFFF > m_wDesc_Tree_ID)
|
|
)
|
|
{
|
|
m_wDesc_Tree_ID ++;
|
|
l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc)))
|
|
CP7Trace_Desc(m_cMemory,
|
|
m_wDesc_Tree_ID,
|
|
i_wLine,
|
|
(i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0,
|
|
i_pFile,
|
|
i_pFunction,
|
|
l_pKeys
|
|
);
|
|
//in stack we have pointer of the function and then format, 2 values
|
|
m_cDescM_Tree.Push(l_pDesc, l_pKeys);
|
|
}
|
|
}
|
|
|
|
if ( (NULL == l_pDesc)
|
|
|| (FALSE == l_pDesc->Is_Initialized())
|
|
)
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
//increase chunks count if it is necessary
|
|
if ((m_pChk_Curs + 8) >= m_pChk_Tail)
|
|
{
|
|
if (FALSE == Inc_Chunks(16))
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pChunk = m_pChk_Curs;
|
|
l_dwSize = m_dwChk_Size;
|
|
|
|
//trace description have to send again
|
|
if (m_sStatus.dwResets != l_pDesc->Get_Resets())
|
|
{
|
|
l_pDesc->Set_Resets(m_sStatus.dwResets);
|
|
|
|
l_bDesc = TRUE;
|
|
l_pChunk->pData = l_pDesc->Get_Buffer(&l_pChunk->dwSize);
|
|
l_dwSize += l_pChunk->dwSize;
|
|
l_pChunk ++;
|
|
}
|
|
|
|
m_sHeader_Data.bLevel = (tUINT8)i_eLevel;
|
|
m_sHeader_Data.bProcessor = (tUINT8)CProc::Get_Processor();
|
|
m_sHeader_Data.dwThreadID = CProc::Get_Thread_Id();
|
|
m_sHeader_Data.wID = l_pDesc->Get_ID();
|
|
m_sHeader_Data.dwSequence = m_dwSequence;
|
|
|
|
if (! m_sConf.pTimestamp_Callback )
|
|
{
|
|
m_sHeader_Data.qwTimer = GetPerformanceCounter();
|
|
}
|
|
else
|
|
{
|
|
m_sHeader_Data.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext);
|
|
}
|
|
|
|
l_pChunk->dwSize = sizeof(m_sHeader_Data);
|
|
l_pChunk->pData = &m_sHeader_Data;
|
|
|
|
//we should also add all variable parameters length ... later
|
|
l_szTrace = sizeof(m_sHeader_Data);
|
|
//SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, );
|
|
//m_sHeader_Data.sCommon.dwSize = sizeof(m_sHeader_Data);
|
|
|
|
l_pChunk ++;
|
|
|
|
//adding string message to chunk
|
|
if (!i_pMessage)
|
|
{
|
|
i_pMessage = TM("NULL");
|
|
}
|
|
|
|
l_pChunk->dwSize = (tUINT32)((PStrLen(i_pMessage) + 1) * sizeof(tXCHAR));
|
|
l_pChunk->pData = (void*)i_pMessage;
|
|
l_szTrace += l_pChunk->dwSize;
|
|
|
|
l_pChunk++;
|
|
|
|
//Put extensions.../////////////////////////////////////////////////////////////
|
|
if (i_hModule)
|
|
{
|
|
#if defined(__linux__) //fix alignment and GCC warnings
|
|
memcpy(m_pExtensions, &(((sP7Trace_Module*)i_hModule)->wModuleID), sizeof(tUINT16));
|
|
#else
|
|
*(tUINT16*)m_pExtensions = ((sP7Trace_Module*)i_hModule)->wModuleID;
|
|
#endif
|
|
|
|
m_pExtensions[2] = (tUINT8)EP7TRACE_EXT_MODULE_ID;
|
|
m_pExtensions[3] = 1;
|
|
l_pChunk->pData = m_pExtensions;
|
|
l_pChunk->dwSize = 4u;
|
|
}
|
|
else
|
|
{
|
|
m_pExtensions[0] = 0;
|
|
l_pChunk->pData = m_pExtensions;
|
|
l_pChunk->dwSize = 1u;
|
|
}
|
|
|
|
l_szTrace += l_pChunk->dwSize;
|
|
SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, l_szTrace);
|
|
l_pChunk ++;
|
|
|
|
|
|
l_dwSize += (tUINT32)l_szTrace;
|
|
|
|
if (ECLIENT_STATUS_OK != m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(l_pChunk - m_pChk_Head),
|
|
l_dwSize
|
|
)
|
|
)
|
|
{
|
|
//if delivery was failed and we try to deliver also trace description
|
|
//we set marker that is should be redelivered next time
|
|
if (l_bDesc)
|
|
{
|
|
l_pDesc->Set_Resets(RESET_UNDEFINED);
|
|
}
|
|
|
|
l_bReturn = FALSE;
|
|
}
|
|
else
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
|
|
|
|
return l_bReturn;
|
|
}// Trace_Managed
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Trace_Raw
|
|
__forceinline tBOOL CP7Trace::Trace_Raw(tUINT16 i_wTrace_ID,
|
|
eP7Trace_Level i_eLevel,
|
|
IP7_Trace::hModule i_hModule,
|
|
tUINT16 i_wLine,
|
|
const char *i_pFile,
|
|
const char *i_pFunction,
|
|
tKeyType *i_pKey,
|
|
const tXCHAR **i_ppFormat,
|
|
va_list *i_pVa_List
|
|
)
|
|
{
|
|
tBOOL l_bReturn = TRUE;
|
|
tUINT32 l_dwSize = 0;
|
|
CP7Trace_Desc *l_pDesc = NULL;
|
|
tINT32 *l_pBlocks = NULL;
|
|
tUINT32 l_dwBCount = 0;
|
|
tUINT8 *l_pVArgs = (tUINT8*)(i_ppFormat) + sizeof(tXCHAR*);
|
|
tBOOL l_bDesc = FALSE;
|
|
size_t l_szTrace = 0;
|
|
sP7C_Data_Chunk *l_pChunk; //we do not initialize it here, we do it later
|
|
|
|
LOCK_ENTER(m_sCS);
|
|
|
|
m_dwSequence ++;
|
|
|
|
if ( (FALSE == m_bActive)
|
|
|| (FALSE == m_sStatus.bConnected)
|
|
|| ( ((i_hModule) && (i_eLevel < ((sP7Trace_Module*)i_hModule)->eVerbosity))
|
|
|| ((!i_hModule) && (i_eLevel < m_eVerbosity))
|
|
)
|
|
)
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//if user specify direct Trace ID
|
|
if ( (1 <= i_wTrace_ID)
|
|
&& (P7_TRACE_DESC_HARDCODED_COUNT > i_wTrace_ID)
|
|
)
|
|
{
|
|
l_pDesc = m_pDesc_Array[i_wTrace_ID];
|
|
if (NULL == l_pDesc)
|
|
{
|
|
l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc)))
|
|
CP7Trace_Desc(m_cMemory,
|
|
i_wTrace_ID,
|
|
i_wLine,
|
|
(i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0,
|
|
i_pFile,
|
|
i_pFunction,
|
|
i_ppFormat,
|
|
i_pKey,
|
|
m_dwFlags
|
|
);
|
|
m_pDesc_Array[i_wTrace_ID] = l_pDesc;
|
|
|
|
#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
if ((l_pDesc->Get_Arguments_Count() * 16) > m_szVargs)
|
|
{
|
|
m_szVargs = l_pDesc->Get_Arguments_Count() * 16;
|
|
m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else //if we should use map to find it
|
|
{
|
|
//This moment should be clarified:
|
|
//Here we made search through RB tree by key. Key consist of 2 values
|
|
// - address of function
|
|
// - address of format string
|
|
//They located in stack [i_pFunction][*i_ppFormat]
|
|
//Function eTrace work with stack of upper function like Trace(...)
|
|
//and we should operate by stack of that function. This is why here
|
|
//we get i_ppFormat, convert it to pointer (4 or 8 bytes depending on OS)
|
|
//and subtract one element to get pointer to the function name.
|
|
l_pDesc = m_cDescU_Tree.Find(i_pKey);
|
|
if ( (NULL == l_pDesc)
|
|
&& (0xFFFF > m_wDesc_Tree_ID)
|
|
)
|
|
{
|
|
m_wDesc_Tree_ID ++;
|
|
l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc)))
|
|
CP7Trace_Desc(m_cMemory,
|
|
m_wDesc_Tree_ID,
|
|
i_wLine,
|
|
(i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0,
|
|
i_pFile,
|
|
i_pFunction,
|
|
i_ppFormat,
|
|
i_pKey,
|
|
m_dwFlags
|
|
);
|
|
//in stack we have pointer of the function and then format, 2 values
|
|
m_cDescU_Tree.Push(l_pDesc, i_pKey);
|
|
|
|
#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
if ((l_pDesc->Get_Arguments_Count() * 16) > m_szVargs)
|
|
{
|
|
m_szVargs = l_pDesc->Get_Arguments_Count() * 16;
|
|
m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( (NULL == l_pDesc)
|
|
|| (FALSE == l_pDesc->Is_Initialized())
|
|
//|| (l_pFormat != l_pDesc->Get_Key())
|
|
)
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
l_pBlocks = l_pDesc->Get_Blocks(&l_dwBCount);
|
|
//increase chunks count if it is necessary
|
|
if ( (l_dwBCount)
|
|
&& ((m_pChk_Curs + l_dwBCount + TRACE_EXTRA_CHUNKS) >= m_pChk_Tail)
|
|
)
|
|
{
|
|
if (FALSE == Inc_Chunks(l_dwBCount + TRACE_EXTRA_CHUNKS))
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
l_pChunk = m_pChk_Curs;
|
|
l_dwSize = m_dwChk_Size;
|
|
|
|
//trace description have to send again
|
|
if (m_sStatus.dwResets != l_pDesc->Get_Resets())
|
|
{
|
|
l_pDesc->Set_Resets(m_sStatus.dwResets);
|
|
|
|
l_bDesc = TRUE;
|
|
l_pChunk->pData = l_pDesc->Get_Buffer(&l_pChunk->dwSize);
|
|
l_dwSize += l_pChunk->dwSize;
|
|
l_pChunk ++;
|
|
}
|
|
|
|
//we should also add all variable parameters length ... later
|
|
l_szTrace = sizeof(m_sHeader_Data);
|
|
//SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, );
|
|
//m_sHeader_Data.sCommon.dwSize = sizeof(m_sHeader_Data);
|
|
|
|
m_sHeader_Data.bLevel = (tUINT8)i_eLevel;
|
|
m_sHeader_Data.bProcessor = (tUINT8)CProc::Get_Processor();
|
|
m_sHeader_Data.dwThreadID = CProc::Get_Thread_Id();
|
|
m_sHeader_Data.wID = l_pDesc->Get_ID();
|
|
m_sHeader_Data.dwSequence = m_dwSequence;
|
|
|
|
if (! m_sConf.pTimestamp_Callback )
|
|
{
|
|
m_sHeader_Data.qwTimer = GetPerformanceCounter();
|
|
}
|
|
else
|
|
{
|
|
m_sHeader_Data.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext);
|
|
}
|
|
|
|
l_pChunk->dwSize = sizeof(m_sHeader_Data);
|
|
l_pChunk->pData = &m_sHeader_Data;
|
|
|
|
l_pChunk ++;
|
|
|
|
//case for platforms where variadic arguments located in stack in specific order
|
|
//or using general purposes registers
|
|
#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION)
|
|
{
|
|
tUINT32 l_dwArgC;
|
|
const sP7Trace_Arg *l_pArgV = l_pDesc->Get_Arguments(l_dwArgC);
|
|
l_pVArgs = m_pVargs;
|
|
while (l_dwArgC--)
|
|
{
|
|
#if defined (GTX32)
|
|
if (4 == l_pArgV->bSize) //most probable case
|
|
{
|
|
*(tUINT32*)l_pVArgs = va_arg(*i_pVa_List, tUINT32);
|
|
}
|
|
else
|
|
#endif
|
|
if (8 == l_pArgV->bSize)
|
|
{
|
|
//GCC sometimes optimizes storing of double values and access to it requires
|
|
//specific case, "bardak i razruha v golovah"
|
|
if (P7TRACE_ARG_TYPE_DOUBLE != l_pArgV->bType)
|
|
{
|
|
//in some platforms access to 64 not aligned variable is illegal, if it
|
|
//the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h
|
|
#if defined(P7TRACE_64BITS_ALIGNED_ACCESS)
|
|
tUINT64 l_qwVal = va_arg(*i_pVa_List, tUINT64);
|
|
memcpy(l_pVArgs, &l_qwVal, sizeof(tUINT64));
|
|
#else
|
|
*(tUINT64*)l_pVArgs = va_arg(*i_pVa_List, tUINT64);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//in some platforms access to 64 not aligned variable is illegal, if it
|
|
//the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h
|
|
#if defined(P7TRACE_64BITS_ALIGNED_ACCESS)
|
|
double l_qwVal = va_arg(*i_pVa_List, double);
|
|
memcpy(l_pVArgs, &l_qwVal, sizeof(double));
|
|
#else
|
|
*(double*)l_pVArgs = va_arg(*i_pVa_List, double);
|
|
#endif
|
|
}
|
|
}
|
|
else if (0 == l_pArgV->bSize)
|
|
{
|
|
*(void**)l_pVArgs = va_arg(*i_pVa_List, void*);
|
|
l_pVArgs += SIZE_OF_ARG(void*); //String has 0 size (0 == l_pArgV->bSize)
|
|
}
|
|
else //if (SIZE_OF_ARG(uintmax_t) == l_pArgV->bSize)
|
|
{
|
|
//in some platforms access to 64 not aligned variable is illegal, if it
|
|
//the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h
|
|
#if defined(P7TRACE_64BITS_ALIGNED_ACCESS)
|
|
uintmax_t l_qwVal = va_arg(*i_pVa_List, uintmax_t);
|
|
memcpy(l_pVArgs, &l_qwVal, sizeof(uintmax_t));
|
|
#else
|
|
*(uintmax_t*)l_pVArgs = va_arg(*i_pVa_List, uintmax_t);
|
|
#endif
|
|
}
|
|
|
|
l_pVArgs += l_pArgV->bSize;
|
|
l_pArgV++;
|
|
}
|
|
l_pVArgs = m_pVargs;
|
|
}
|
|
#endif
|
|
|
|
while (l_dwBCount --)
|
|
{
|
|
if (0 <= (*l_pBlocks))
|
|
{
|
|
l_pChunk->dwSize = (*l_pBlocks);
|
|
l_pChunk->pData = l_pVArgs;
|
|
l_pVArgs += (*l_pBlocks);
|
|
}
|
|
else if (P7TRACE_ITEM_BLOCK_ASTRING == (*l_pBlocks))
|
|
{
|
|
l_pChunk->pData = *(char**)l_pVArgs;
|
|
|
|
if (l_pChunk->pData)
|
|
{
|
|
l_pChunk->dwSize = (tUINT32)strlen(*(char**)l_pVArgs) + 1;
|
|
}
|
|
else
|
|
{
|
|
l_pChunk->pData = const_cast<char*>("(NULL)");
|
|
l_pChunk->dwSize = 7u;
|
|
}
|
|
|
|
l_pVArgs += sizeof(char*);
|
|
}
|
|
#ifndef UTF8_ENCODING
|
|
else if (P7TRACE_ITEM_BLOCK_USTRING16 == (*l_pBlocks))
|
|
{
|
|
l_pChunk->pData = *(wchar_t**)l_pVArgs;
|
|
|
|
if (l_pChunk->pData)
|
|
{
|
|
l_pChunk->dwSize = (tUINT32)((wcslen(*(wchar_t**)l_pVArgs) + 1) * sizeof(wchar_t));
|
|
}
|
|
else
|
|
{
|
|
l_pChunk->pData = const_cast<wchar_t*>(L"(NULL)");
|
|
l_pChunk->dwSize = sizeof(wchar_t) * 7u;
|
|
}
|
|
|
|
l_pVArgs += sizeof(wchar_t*);
|
|
}
|
|
#else
|
|
else if (P7TRACE_ITEM_BLOCK_USTRING32 == (*l_pBlocks))
|
|
{
|
|
l_pChunk->pData = *(wchar_t**)l_pVArgs;
|
|
|
|
if (l_pChunk->pData)
|
|
{
|
|
l_pChunk->dwSize = (tUINT32)((wcslen(*(wchar_t**)l_pVArgs) + 1) * sizeof(wchar_t));
|
|
}
|
|
else
|
|
{
|
|
l_pChunk->pData = const_cast<wchar_t*>(L"(NULL)");
|
|
l_pChunk->dwSize = sizeof(wchar_t) * 7u;
|
|
}
|
|
|
|
l_pVArgs += sizeof(wchar_t*);
|
|
}
|
|
#endif
|
|
else if (P7TRACE_ITEM_BLOCK_ASTRING_FIX == (*l_pBlocks))
|
|
{
|
|
l_pChunk->pData = const_cast<char*>("([x]s is unsupported by P7)");
|
|
l_pChunk->dwSize = sizeof(char) * 28u;
|
|
l_pVArgs += sizeof(char*);
|
|
}
|
|
else if (P7TRACE_ITEM_BLOCK_WSTRING_FIX == (*l_pBlocks))
|
|
{
|
|
l_pChunk->pData = const_cast<wchar_t*>(L"([x]s is unsupported by P7)");
|
|
l_pChunk->dwSize = sizeof(wchar_t) * 28u;
|
|
l_pVArgs += sizeof(wchar_t*);
|
|
}
|
|
|
|
l_szTrace += (size_t)l_pChunk->dwSize;
|
|
|
|
l_pChunk ++;
|
|
l_pBlocks++;
|
|
}
|
|
|
|
//Put extensions.../////////////////////////////////////////////////////////////
|
|
if (i_hModule)
|
|
{
|
|
#if defined(__linux__) //fix alignment and GCC warnings
|
|
memcpy(m_pExtensions, &(((sP7Trace_Module*)i_hModule)->wModuleID), sizeof(tUINT16));
|
|
#else
|
|
*(tUINT16*)m_pExtensions = ((sP7Trace_Module*)i_hModule)->wModuleID;
|
|
#endif
|
|
|
|
m_pExtensions[2] = (tUINT8)EP7TRACE_EXT_MODULE_ID;
|
|
m_pExtensions[3] = 1;
|
|
l_pChunk->pData = m_pExtensions;
|
|
l_pChunk->dwSize = 4u;
|
|
}
|
|
else
|
|
{
|
|
m_pExtensions[0] = 0;
|
|
l_pChunk->pData = m_pExtensions;
|
|
l_pChunk->dwSize = 1u;
|
|
}
|
|
|
|
l_szTrace += l_pChunk->dwSize;
|
|
SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, l_szTrace);
|
|
l_pChunk ++;
|
|
|
|
l_dwSize += (tUINT32)l_szTrace;//m_sHeader_Data.sCommon.dwSize;
|
|
|
|
if (ECLIENT_STATUS_OK != m_pClient->Sent(m_dwChannel_ID,
|
|
m_pChk_Head,
|
|
(tUINT32)(l_pChunk - m_pChk_Head),
|
|
l_dwSize
|
|
)
|
|
)
|
|
{
|
|
//if delivery was failed and we try to deliver also trace description
|
|
//we set marker that is should be redelivered next time
|
|
if (l_bDesc)
|
|
{
|
|
l_pDesc->Set_Resets(RESET_UNDEFINED);
|
|
}
|
|
|
|
l_bReturn = FALSE;
|
|
}
|
|
else
|
|
{
|
|
m_pChk_Curs = m_pChk_Head;
|
|
m_dwChk_Size = 0;
|
|
}
|
|
|
|
l_lblExit:
|
|
LOCK_EXIT(m_sCS);
|
|
|
|
return l_bReturn;
|
|
}// Trace_Raw
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Inc_Chunks
|
|
__forceinline tBOOL CP7Trace::Inc_Chunks(tUINT32 i_dwInc)
|
|
{
|
|
size_t l_szUsed = m_pChk_Curs - m_pChk_Head;
|
|
sP7C_Data_Chunk *l_pChunks = (sP7C_Data_Chunk*)realloc(m_pChk_Head,
|
|
(m_dwChk_Count + i_dwInc) * sizeof(sP7C_Data_Chunk)
|
|
);
|
|
|
|
if (!l_pChunks)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
m_pChk_Head = l_pChunks;
|
|
m_pChk_Curs = m_pChk_Head + l_szUsed; //set current to new/old location
|
|
m_dwChk_Count += i_dwInc;
|
|
m_pChk_Tail = m_pChk_Head + m_dwChk_Count;
|
|
|
|
return TRUE;
|
|
}// Inc_Chunks
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Is_VarArgs()
|
|
//Some processors have funny stack alignment rules, for example arm under 32 bits
|
|
//for 64 bits variables request 64 bit address stack alignment, some uses gen.
|
|
//registers, some changes order, etc.
|
|
tBOOL CP7Trace::Is_VarArgs(const CP7Trace::sStack_Desc *i_pDesc, ...)
|
|
{
|
|
const tUINT8 *l_pData = (const tUINT8 *)&i_pDesc + sizeof(void*);
|
|
tBOOL l_bReturn = TRUE;
|
|
va_list l_pVal;
|
|
|
|
va_start(l_pVal, i_pDesc);
|
|
while (1)
|
|
{
|
|
if (CP7Trace::sStack_Desc::eTypeU32 == i_pDesc->eType)
|
|
{
|
|
if (*(tUINT32*)l_pData != va_arg(l_pVal, tUINT32))
|
|
{
|
|
l_bReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
l_pData += SIZE_OF_ARG(tUINT32);
|
|
}
|
|
else if (CP7Trace::sStack_Desc::eTypeU64 == i_pDesc->eType)
|
|
{
|
|
if (*(tUINT64*)l_pData != va_arg(l_pVal, tUINT64))
|
|
{
|
|
l_bReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
l_pData += SIZE_OF_ARG(tUINT64);
|
|
}
|
|
else if (CP7Trace::sStack_Desc::eTypeD64 == i_pDesc->eType)
|
|
{
|
|
if (*(tDOUBLE*)l_pData != va_arg(l_pVal, tDOUBLE))
|
|
{
|
|
l_bReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
l_pData += SIZE_OF_ARG(tUINT64);
|
|
}
|
|
|
|
if (i_pDesc->bLast)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
i_pDesc++;
|
|
}
|
|
}
|
|
|
|
va_end(l_pVal);
|
|
|
|
return l_bReturn;
|
|
}
|