You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
627 lines
16 KiB
627 lines
16 KiB
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//===========================================================================// |
|
|
|
#include "tier0/platform.h" |
|
|
|
#if defined( PLATFORM_WINDOWS_PC ) |
|
#define WIN_32_LEAN_AND_MEAN |
|
#include <windows.h> // Currently needed for IsBadReadPtr and IsBadWritePtr |
|
#pragma comment(lib,"user32.lib") // For MessageBox |
|
#endif |
|
|
|
#include "tier0/minidump.h" |
|
#include "tier0/stacktools.h" |
|
|
|
#include <assert.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <stdarg.h> |
|
#include <stdlib.h> |
|
#include "color.h" |
|
#include "tier0/dbg.h" |
|
#include "tier0/threadtools.h" |
|
#include "tier0/icommandline.h" |
|
#include <math.h> |
|
|
|
#if defined( _X360 ) |
|
#include "xbox/xbox_console.h" |
|
#endif |
|
|
|
#include "tier0/etwprof.h" |
|
|
|
#ifndef STEAM |
|
#define PvRealloc realloc |
|
#define PvAlloc malloc |
|
#endif |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) |
|
#pragma optimize( "g", off ) //variable argument functions seem to screw up stack walking unless this optimization is disabled |
|
#pragma warning( disable: 4748 ) // Turn off the warning telling us that optimizations are off if /GS is on |
|
#endif |
|
|
|
DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_LOADING, "LOADING" ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Stack attachment management |
|
//----------------------------------------------------------------------------- |
|
#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) |
|
|
|
static bool s_bCallStacksWithAllWarnings = false; //if true, attach a call stack to every SPEW_WARNING message. Warning()/DevWarning()/... |
|
static int s_iWarningMaxCallStackLength = 5; |
|
#define AutomaticWarningCallStackLength() (s_bCallStacksWithAllWarnings ? s_iWarningMaxCallStackLength : 0) |
|
|
|
void _Warning_AlwaysSpewCallStack_Enable( bool bEnable ) |
|
{ |
|
s_bCallStacksWithAllWarnings = bEnable; |
|
} |
|
|
|
void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength ) |
|
{ |
|
s_iWarningMaxCallStackLength = iMaxCallStackLength; |
|
} |
|
|
|
static bool s_bCallStacksWithAllErrors = false; //if true, attach a call stack to every SPEW_ERROR message. Mostly just Error() |
|
static int s_iErrorMaxCallStackLength = 20; //default to higher output with an error since we're quitting anyways |
|
#define AutomaticErrorCallStackLength() (s_bCallStacksWithAllErrors ? s_iErrorMaxCallStackLength : 0) |
|
|
|
void _Error_AlwaysSpewCallStack_Enable( bool bEnable ) |
|
{ |
|
s_bCallStacksWithAllErrors = bEnable; |
|
} |
|
|
|
void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength ) |
|
{ |
|
s_iErrorMaxCallStackLength = iMaxCallStackLength; |
|
} |
|
|
|
#else //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) |
|
|
|
#define AutomaticWarningCallStackLength() 0 |
|
#define AutomaticErrorCallStackLength() 0 |
|
|
|
void _Warning_AlwaysSpewCallStack_Enable( bool bEnable ) |
|
{ |
|
} |
|
|
|
void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength ) |
|
{ |
|
} |
|
|
|
void _Error_AlwaysSpewCallStack_Enable( bool bEnable ) |
|
{ |
|
} |
|
|
|
void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength ) |
|
{ |
|
} |
|
|
|
#endif //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) |
|
|
|
void _ExitOnFatalAssert( const tchar* pFile, int line ) |
|
{ |
|
Log_Msg( LOG_ASSERT, _T("Fatal assert failed: %s, line %d. Application exiting.\n"), pFile, line ); |
|
|
|
// only write out minidumps if we're not in the debugger |
|
if ( !Plat_IsInDebugSession() ) |
|
{ |
|
WriteMiniDump(); |
|
} |
|
|
|
Log_Msg( LOG_DEVELOPER, _T("_ExitOnFatalAssert\n") ); |
|
Plat_ExitProcess( EXIT_FAILURE ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Templates to assist in validating pointers: |
|
//----------------------------------------------------------------------------- |
|
PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count/* = 1*/ ) |
|
{ |
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
Assert( !IsBadReadPtr( ptr, count ) ); |
|
#else |
|
Assert( !count || ptr ); |
|
#endif |
|
} |
|
|
|
PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count/* = 1*/ ) |
|
{ |
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
Assert( !IsBadWritePtr( ptr, count ) ); |
|
#else |
|
Assert( !count || ptr ); |
|
#endif |
|
} |
|
|
|
PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count/* = 1*/ ) |
|
{ |
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
Assert(!( IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr,count))); |
|
#else |
|
Assert( !count || ptr ); |
|
#endif |
|
} |
|
|
|
PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar/* = 0xFFFFFF */ ) |
|
{ |
|
#if defined( _WIN32 ) && !defined( _X360 ) |
|
#ifdef TCHAR_IS_CHAR |
|
Assert( !IsBadStringPtr( ptr, maxchar ) ); |
|
#else |
|
Assert( !IsBadStringPtrW( ptr, maxchar ) ); |
|
#endif |
|
#else |
|
Assert( ptr ); |
|
#endif |
|
} |
|
|
|
void AppendCallStackToLogMessage( tchar *formattedMessage, int iMessageLength, int iAppendCallStackLength ) |
|
{ |
|
#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) |
|
# if defined( TCHAR_IS_CHAR ) //I'm horrible with unicode and I don't plan on testing this with wide characters just yet |
|
if( iAppendCallStackLength > 0 ) |
|
{ |
|
int iExistingMessageLength = (int)strlen( formattedMessage ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe |
|
formattedMessage += iExistingMessageLength; |
|
iMessageLength -= iExistingMessageLength; |
|
|
|
if( iMessageLength <= 32 ) |
|
return; //no room for anything useful |
|
|
|
//append directly to the spew message |
|
if( (iExistingMessageLength > 0) && (formattedMessage[-1] == '\n') ) |
|
{ |
|
--formattedMessage; |
|
++iMessageLength; |
|
} |
|
|
|
//append preface |
|
int iAppendedLength = _snprintf( formattedMessage, iMessageLength, _T("\nCall Stack:\n\t") ); |
|
|
|
void **CallStackBuffer = (void **)stackalloc( iAppendCallStackLength * sizeof( void * ) ); |
|
int iCount = GetCallStack( CallStackBuffer, iAppendCallStackLength, 2 ); |
|
if( TranslateStackInfo( CallStackBuffer, iCount, formattedMessage + iAppendedLength, iMessageLength - iAppendedLength, _T("\n\t") ) == 0 ) |
|
{ |
|
//failure |
|
formattedMessage[0] = '\0'; //this is pointing at where we wrote "\nCall Stack:\n\t" |
|
} |
|
else |
|
{ |
|
iAppendedLength += (int)strlen( formattedMessage + iAppendedLength ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe |
|
|
|
if( iAppendedLength < iMessageLength ) |
|
{ |
|
formattedMessage[iAppendedLength] = '\n'; //Add another newline. |
|
++iAppendedLength; |
|
|
|
formattedMessage[iAppendedLength] = '\0'; |
|
} |
|
} |
|
} |
|
# else |
|
AssertMsg( false, "Fixme" ); |
|
# endif |
|
#endif |
|
} |
|
|
|
// Forward declare for internal use only. |
|
CLoggingSystem *GetGlobalLoggingSystem(); |
|
|
|
#define Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, AppendCallStackLength ) \ |
|
do \ |
|
{ \ |
|
CLoggingSystem *pLoggingSystem = GetGlobalLoggingSystem(); \ |
|
if ( pLoggingSystem->IsChannelEnabled( Channel, Severity ) ) \ |
|
{ \ |
|
tchar formattedMessage[MAX_LOGGING_MESSAGE_LENGTH]; \ |
|
va_list args; \ |
|
va_start( args, MessageFormat ); \ |
|
Tier0Internal_vsntprintf( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, MessageFormat, args ); \ |
|
va_end( args ); \ |
|
AppendCallStackToLogMessage( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, AppendCallStackLength ); \ |
|
pLoggingSystem->LogDirect( Channel, Severity, Color, formattedMessage ); \ |
|
} \ |
|
} while( 0 ) |
|
|
|
#define Log_LegacyHelperColor( Channel, Severity, Color, MessageFormat ) Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, 0 ) |
|
|
|
#define Log_LegacyHelper_Stack( Channel, Severity, MessageFormat, AppendCallStackLength ) Log_LegacyHelperColor_Stack( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat, AppendCallStackLength ) |
|
#define Log_LegacyHelper( Channel, Severity, MessageFormat ) Log_LegacyHelperColor( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat ) |
|
|
|
|
|
void Msg( const tchar* pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper( LOG_GENERAL, LS_MESSAGE, pMsgFormat ); |
|
} |
|
|
|
void Warning( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, AutomaticWarningCallStackLength() ); |
|
} |
|
|
|
void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, iMaxCallStackLength ); |
|
} |
|
|
|
|
|
void Error( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, AutomaticErrorCallStackLength() ); |
|
} |
|
|
|
void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, iMaxCallStackLength ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// A couple of super-common dynamic spew messages, here for convenience |
|
// These looked at the "developer" group, print if it's level 1 or higher |
|
//----------------------------------------------------------------------------- |
|
void DevMsg( int level, const tchar* pMsgFormat, ... ) |
|
{ |
|
LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER; |
|
Log_LegacyHelper( channel, LS_MESSAGE, pMsgFormat ); |
|
} |
|
|
|
|
|
void DevWarning( int level, const tchar *pMsgFormat, ... ) |
|
{ |
|
LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER; |
|
Log_LegacyHelper( channel, LS_WARNING, pMsgFormat ); |
|
} |
|
|
|
void DevMsg( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper( LOG_DEVELOPER, LS_MESSAGE, pMsgFormat ); |
|
} |
|
|
|
void DevWarning( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper( LOG_DEVELOPER, LS_WARNING, pMsgFormat ); |
|
} |
|
|
|
void ConColorMsg( const Color& clr, const tchar* pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelperColor( LOG_CONSOLE, LS_MESSAGE, clr, pMsgFormat ); |
|
} |
|
|
|
void ConMsg( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper( LOG_CONSOLE, LS_MESSAGE, pMsgFormat ); |
|
} |
|
|
|
void ConDMsg( const tchar *pMsgFormat, ... ) |
|
{ |
|
Log_LegacyHelper( LOG_DEVELOPER_CONSOLE, LS_MESSAGE, pMsgFormat ); |
|
} |
|
|
|
// If we don't have a function from math.h, then it doesn't link certain floating-point |
|
// functions in and printfs with %f cause runtime errors in the C libraries. |
|
PLATFORM_INTERFACE float CrackSmokingCompiler( float a ) |
|
{ |
|
return (float)fabs( a ); |
|
} |
|
|
|
void* Plat_SimpleLog( const tchar* file, int line ) |
|
{ |
|
FILE* f = _tfopen( _T("simple.log"), _T("at+") ); |
|
_ftprintf( f, _T("%s:%i\n"), file, line ); |
|
fclose( f ); |
|
|
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: For debugging startup times, etc. |
|
// Input : *fmt - |
|
// ... - |
|
//----------------------------------------------------------------------------- |
|
void COM_TimestampedLog( char const *fmt, ... ) |
|
{ |
|
static float s_LastStamp = 0.0; |
|
static bool s_bShouldLog = false; |
|
static bool s_bShouldLogToConsole = false; |
|
static bool s_bShouldLogToETW = false; |
|
static bool s_bChecked = false; |
|
static bool s_bFirstWrite = false; |
|
|
|
if ( !s_bChecked ) |
|
{ |
|
s_bShouldLog = ( CommandLine()->CheckParm( "-profile" ) ) ? true : false; |
|
s_bShouldLogToConsole = ( CommandLine()->ParmValue( "-profile", 0.0f ) != 0.0f ) ? true : false; |
|
|
|
s_bShouldLogToETW = ( CommandLine()->CheckParm( "-etwprofile" ) ) ? true : false; |
|
if ( s_bShouldLogToETW ) |
|
{ |
|
s_bShouldLog = true; |
|
} |
|
|
|
s_bChecked = true; |
|
} |
|
if ( !s_bShouldLog ) |
|
{ |
|
return; |
|
} |
|
|
|
char string[1024]; |
|
va_list argptr; |
|
va_start( argptr, fmt ); |
|
Tier0Internal_vsnprintf( string, sizeof( string ), fmt, argptr ); |
|
va_end( argptr ); |
|
|
|
float curStamp = Plat_FloatTime(); |
|
|
|
#if defined( _X360 ) |
|
XBX_rTimeStampLog( curStamp, string ); |
|
#elif defined( _PS3 ) |
|
Log_Warning( LOG_LOADING, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string ); |
|
#endif |
|
|
|
if ( IsPC() ) |
|
{ |
|
// If ETW profiling is enabled then do it only. |
|
if ( s_bShouldLogToETW ) |
|
{ |
|
ETWMark( string ); |
|
} |
|
else |
|
{ |
|
if ( !s_bFirstWrite ) |
|
{ |
|
unlink( "timestamped.log" ); |
|
s_bFirstWrite = true; |
|
} |
|
|
|
FILE* fp = fopen( "timestamped.log", "at+" ); |
|
fprintf( fp, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string ); |
|
fclose( fp ); |
|
} |
|
|
|
if ( s_bShouldLogToConsole ) |
|
{ |
|
Msg( "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string ); |
|
} |
|
} |
|
|
|
s_LastStamp = curStamp; |
|
} |
|
|
|
#ifdef IS_WINDOWS_PC |
|
|
|
class CHardwareBreakPoint |
|
{ |
|
public: |
|
|
|
enum EOpCode |
|
{ |
|
BRK_SET = 0, |
|
BRK_UNSET, |
|
}; |
|
|
|
CHardwareBreakPoint() |
|
{ |
|
m_eOperation = BRK_SET; |
|
m_pvAddress = 0; |
|
m_hThread = 0; |
|
m_hThreadEvent = 0; |
|
m_nRegister = 0; |
|
m_bSuccess = false; |
|
} |
|
|
|
const void *m_pvAddress; |
|
HANDLE m_hThread; |
|
EHardwareBreakpointType m_eType; |
|
EHardwareBreakpointSize m_eSize; |
|
HANDLE m_hThreadEvent; |
|
int m_nRegister; |
|
EOpCode m_eOperation; |
|
bool m_bSuccess; |
|
|
|
static void SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue ); |
|
static DWORD WINAPI ThreadProc( LPVOID lpParameter ); |
|
}; |
|
|
|
void CHardwareBreakPoint::SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue ) |
|
{ |
|
DWORD_PTR mask = (1 << bits) - 1; |
|
dw = (dw & ~(mask << lowBit)) | (newValue << lowBit); |
|
} |
|
|
|
DWORD WINAPI CHardwareBreakPoint::ThreadProc( LPVOID lpParameter ) |
|
{ |
|
CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint * >( lpParameter ); |
|
SuspendThread( h->m_hThread ); |
|
|
|
// Get current context |
|
CONTEXT ct = {0}; |
|
ct.ContextFlags = CONTEXT_DEBUG_REGISTERS; |
|
GetThreadContext(h->m_hThread,&ct); |
|
|
|
int FlagBit = 0; |
|
|
|
bool Dr0Busy = false; |
|
bool Dr1Busy = false; |
|
bool Dr2Busy = false; |
|
bool Dr3Busy = false; |
|
if (ct.Dr7 & 1) |
|
Dr0Busy = true; |
|
if (ct.Dr7 & 4) |
|
Dr1Busy = true; |
|
if (ct.Dr7 & 16) |
|
Dr2Busy = true; |
|
if (ct.Dr7 & 64) |
|
Dr3Busy = true; |
|
|
|
if ( h->m_eOperation == CHardwareBreakPoint::BRK_UNSET ) |
|
{ |
|
// Remove |
|
if (h->m_nRegister == 0) |
|
{ |
|
FlagBit = 0; |
|
ct.Dr0 = 0; |
|
Dr0Busy = false; |
|
} |
|
if (h->m_nRegister == 1) |
|
{ |
|
FlagBit = 2; |
|
ct.Dr1 = 0; |
|
Dr1Busy = false; |
|
} |
|
if (h->m_nRegister == 2) |
|
{ |
|
FlagBit = 4; |
|
ct.Dr2 = 0; |
|
Dr2Busy = false; |
|
} |
|
if (h->m_nRegister == 3) |
|
{ |
|
FlagBit = 6; |
|
ct.Dr3 = 0; |
|
Dr3Busy = false; |
|
} |
|
ct.Dr7 &= ~(1 << FlagBit); |
|
} |
|
else |
|
{ |
|
if (!Dr0Busy) |
|
{ |
|
h->m_nRegister = 0; |
|
ct.Dr0 = (DWORD_PTR)h->m_pvAddress; |
|
Dr0Busy = true; |
|
} |
|
else if (!Dr1Busy) |
|
{ |
|
h->m_nRegister = 1; |
|
ct.Dr1 = (DWORD_PTR)h->m_pvAddress; |
|
Dr1Busy = true; |
|
} |
|
else if (!Dr2Busy) |
|
{ |
|
h->m_nRegister = 2; |
|
ct.Dr2 = (DWORD_PTR)h->m_pvAddress; |
|
Dr2Busy = true; |
|
} |
|
else if (!Dr3Busy) |
|
{ |
|
h->m_nRegister = 3; |
|
ct.Dr3 = (DWORD_PTR)h->m_pvAddress; |
|
Dr3Busy = true; |
|
} |
|
else |
|
{ |
|
h->m_bSuccess = false; |
|
ResumeThread(h->m_hThread); |
|
SetEvent(h->m_hThreadEvent); |
|
return 0; |
|
} |
|
|
|
ct.Dr6 = 0; |
|
int st = 0; |
|
if (h->m_eType == BREAKPOINT_EXECUTE) |
|
st = 0; |
|
if (h->m_eType == BREAKPOINT_READWRITE) |
|
st = 3; |
|
if (h->m_eType == BREAKPOINT_WRITE) |
|
st = 1; |
|
|
|
int le = 0; |
|
if (h->m_eSize == BREAKPOINT_SIZE_1) |
|
le = 0; |
|
if (h->m_eSize == BREAKPOINT_SIZE_2) |
|
le = 1; |
|
if (h->m_eSize == BREAKPOINT_SIZE_4) |
|
le = 3; |
|
if (h->m_eSize == BREAKPOINT_SIZE_8) |
|
le = 2; |
|
|
|
SetBits( ct.Dr7, 16 + h->m_nRegister*4, 2, st ); |
|
SetBits( ct.Dr7, 18 + h->m_nRegister*4, 2, le ); |
|
SetBits( ct.Dr7, h->m_nRegister*2,1,1); |
|
} |
|
|
|
ct.ContextFlags = CONTEXT_DEBUG_REGISTERS; |
|
SetThreadContext(h->m_hThread,&ct); |
|
|
|
ResumeThread( h->m_hThread ); |
|
h->m_bSuccess = true; |
|
SetEvent( h->m_hThreadEvent ); |
|
return 0; |
|
} |
|
|
|
HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation ) |
|
{ |
|
CHardwareBreakPoint *h = new CHardwareBreakPoint(); |
|
h->m_pvAddress = pvLocation; |
|
h->m_eSize = eSize; |
|
h->m_eType = eType; |
|
HANDLE hThread = GetCurrentThread(); |
|
h->m_hThread = hThread; |
|
|
|
if ( hThread == GetCurrentThread() ) |
|
{ |
|
DWORD nThreadId = GetCurrentThreadId(); |
|
h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId ); |
|
} |
|
|
|
h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); |
|
h->m_eOperation = CHardwareBreakPoint::BRK_SET; // Set Break |
|
CreateThread( 0, 0, CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0, 0 ); |
|
WaitForSingleObject( h->m_hThreadEvent,INFINITE ); |
|
CloseHandle( h->m_hThreadEvent ); |
|
h->m_hThreadEvent = 0; |
|
if ( hThread == GetCurrentThread() ) |
|
{ |
|
CloseHandle( h->m_hThread ); |
|
} |
|
h->m_hThread = hThread; |
|
if ( !h->m_bSuccess ) |
|
{ |
|
delete h; |
|
return (HardwareBreakpointHandle_t)0; |
|
} |
|
return (HardwareBreakpointHandle_t)h; |
|
} |
|
|
|
bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle ) |
|
{ |
|
CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint* >( handle ); |
|
if ( !h ) |
|
{ |
|
return false; |
|
} |
|
|
|
bool bOpened = false; |
|
if ( h->m_hThread == GetCurrentThread() ) |
|
{ |
|
DWORD nThreadId = GetCurrentThreadId(); |
|
h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId ); |
|
bOpened = true; |
|
} |
|
|
|
h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); |
|
h->m_eOperation = CHardwareBreakPoint::BRK_UNSET; // Remove Break |
|
CreateThread( 0,0,CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0,0 ); |
|
WaitForSingleObject( h->m_hThreadEvent, INFINITE ); |
|
CloseHandle( h->m_hThreadEvent ); |
|
h->m_hThreadEvent = 0; |
|
if ( bOpened ) |
|
{ |
|
CloseHandle( h->m_hThread ); |
|
} |
|
delete h; |
|
return true; |
|
} |
|
|
|
#endif // IS_WINDOWS_PC |
|
|
|
|