Counter Strike : Global Offensive Source Code
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.

686 lines
19 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "tier0/platform.h"
  9. #if defined( PLATFORM_WINDOWS_PC )
  10. #define WIN_32_LEAN_AND_MEAN
  11. #include <windows.h> // Currently needed for IsBadReadPtr and IsBadWritePtr
  12. #pragma comment(lib,"user32.lib") // For MessageBox
  13. #endif
  14. #include "tier0/minidump.h"
  15. #include "tier0/stacktools.h"
  16. #include "tier0/etwprof.h"
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include "color.h"
  23. #include "tier0/dbg.h"
  24. #include "tier0/threadtools.h"
  25. #include "tier0/icommandline.h"
  26. #include "tier0/vprof.h"
  27. #include <math.h>
  28. #if defined( _X360 )
  29. #include "xbox/xbox_console.h"
  30. #endif
  31. #ifndef STEAM
  32. #define PvRealloc realloc
  33. #define PvAlloc malloc
  34. #endif
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  38. #pragma optimize( "g", off ) //variable argument functions seem to screw up stack walking unless this optimization is disabled
  39. // Disable this warning: dbg.cpp(479): warning C4748: /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function
  40. #pragma warning( disable : 4748 )
  41. #endif
  42. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_LOADING, "LOADING" );
  43. //-----------------------------------------------------------------------------
  44. // Stack attachment management
  45. //-----------------------------------------------------------------------------
  46. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  47. static bool s_bCallStacksWithAllWarnings = false; //if true, attach a call stack to every SPEW_WARNING message. Warning()/DevWarning()/...
  48. static int s_iWarningMaxCallStackLength = 5;
  49. #define AutomaticWarningCallStackLength() (s_bCallStacksWithAllWarnings ? s_iWarningMaxCallStackLength : 0)
  50. void _Warning_AlwaysSpewCallStack_Enable( bool bEnable )
  51. {
  52. s_bCallStacksWithAllWarnings = bEnable;
  53. }
  54. void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
  55. {
  56. s_iWarningMaxCallStackLength = iMaxCallStackLength;
  57. }
  58. static bool s_bCallStacksWithAllErrors = false; //if true, attach a call stack to every SPEW_ERROR message. Mostly just Error()
  59. static int s_iErrorMaxCallStackLength = 20; //default to higher output with an error since we're quitting anyways
  60. #define AutomaticErrorCallStackLength() (s_bCallStacksWithAllErrors ? s_iErrorMaxCallStackLength : 0)
  61. void _Error_AlwaysSpewCallStack_Enable( bool bEnable )
  62. {
  63. s_bCallStacksWithAllErrors = bEnable;
  64. }
  65. void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
  66. {
  67. s_iErrorMaxCallStackLength = iMaxCallStackLength;
  68. }
  69. #else //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  70. #define AutomaticWarningCallStackLength() 0
  71. #define AutomaticErrorCallStackLength() 0
  72. void _Warning_AlwaysSpewCallStack_Enable( bool bEnable )
  73. {
  74. }
  75. void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
  76. {
  77. }
  78. void _Error_AlwaysSpewCallStack_Enable( bool bEnable )
  79. {
  80. }
  81. void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
  82. {
  83. }
  84. #endif //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  85. // Skip forward past the directory
  86. static const char *SkipToFname( const tchar* pFile )
  87. {
  88. if ( pFile == NULL )
  89. return "unknown";
  90. const tchar* pSlash = _tcsrchr( pFile, '\\' );
  91. const tchar* pSlash2 = _tcsrchr( pFile, '/' );
  92. if (pSlash < pSlash2) pSlash = pSlash2;
  93. return pSlash ? pSlash + 1: pFile;
  94. }
  95. void _ExitOnFatalAssert( const tchar* pFile, int line )
  96. {
  97. Log_Msg( LOG_ASSERT, _T("Fatal assert failed: %s, line %d. Application exiting.\n"), pFile, line );
  98. // only write out minidumps if we're not in the debugger
  99. if ( !Plat_IsInDebugSession() )
  100. {
  101. WriteMiniDump();
  102. }
  103. Log_Msg( LOG_DEVELOPER, _T("_ExitOnFatalAssert\n") );
  104. Plat_ExitProcess( EXIT_FAILURE );
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Templates to assist in validating pointers:
  108. //-----------------------------------------------------------------------------
  109. PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count/* = 1*/ )
  110. {
  111. #if defined( _WIN32 ) && !defined( _X360 )
  112. Assert( !IsBadReadPtr( ptr, count ) );
  113. #else
  114. Assert( !count || ptr );
  115. #endif
  116. }
  117. PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count/* = 1*/ )
  118. {
  119. #if defined( _WIN32 ) && !defined( _X360 )
  120. Assert( !IsBadWritePtr( ptr, count ) );
  121. #else
  122. Assert( !count || ptr );
  123. #endif
  124. }
  125. PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count/* = 1*/ )
  126. {
  127. #if defined( _WIN32 ) && !defined( _X360 )
  128. Assert(!( IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr,count)));
  129. #else
  130. Assert( !count || ptr );
  131. #endif
  132. }
  133. PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar/* = 0xFFFFFF */ )
  134. {
  135. #if defined( _WIN32 ) && !defined( _X360 )
  136. #ifdef TCHAR_IS_CHAR
  137. Assert( !IsBadStringPtr( ptr, maxchar ) );
  138. #else
  139. Assert( !IsBadStringPtrW( ptr, maxchar ) );
  140. #endif
  141. #else
  142. Assert( ptr );
  143. #endif
  144. }
  145. PLATFORM_INTERFACE void AssertValidWStringPtr( const wchar_t* ptr, int maxchar/* = 0xFFFFFF */ )
  146. {
  147. #if defined( _WIN32 ) && !defined( _X360 )
  148. Assert( !IsBadStringPtrW( ptr, maxchar ) );
  149. #else
  150. Assert( ptr );
  151. #endif
  152. }
  153. void AppendCallStackToLogMessage( tchar *formattedMessage, int iMessageLength, int iAppendCallStackLength )
  154. {
  155. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  156. # if defined( TCHAR_IS_CHAR ) //I'm horrible with unicode and I don't plan on testing this with wide characters just yet
  157. if( iAppendCallStackLength > 0 )
  158. {
  159. int iExistingMessageLength = (int)strlen( formattedMessage ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe
  160. formattedMessage += iExistingMessageLength;
  161. iMessageLength -= iExistingMessageLength;
  162. if( iMessageLength <= 32 )
  163. return; //no room for anything useful
  164. //append directly to the spew message
  165. if( (iExistingMessageLength > 0) && (formattedMessage[-1] == '\n') )
  166. {
  167. --formattedMessage;
  168. ++iMessageLength;
  169. }
  170. //append preface
  171. int iAppendedLength = _snprintf( formattedMessage, iMessageLength, _T("\nCall Stack:\n\t") );
  172. void **CallStackBuffer = (void **)stackalloc( iAppendCallStackLength * sizeof( void * ) );
  173. int iCount = GetCallStack( CallStackBuffer, iAppendCallStackLength, 2 );
  174. if( TranslateStackInfo( CallStackBuffer, iCount, formattedMessage + iAppendedLength, iMessageLength - iAppendedLength, _T("\n\t") ) == 0 )
  175. {
  176. //failure
  177. formattedMessage[0] = '\0'; //this is pointing at where we wrote "\nCall Stack:\n\t"
  178. }
  179. else
  180. {
  181. iAppendedLength += (int)strlen( formattedMessage + iAppendedLength ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe
  182. if( iAppendedLength < iMessageLength )
  183. {
  184. formattedMessage[iAppendedLength] = '\n'; //Add another newline.
  185. ++iAppendedLength;
  186. formattedMessage[iAppendedLength] = '\0';
  187. }
  188. }
  189. }
  190. # else
  191. AssertMsg( false, "Fixme" );
  192. # endif
  193. #endif
  194. }
  195. // Forward declare for internal use only.
  196. CLoggingSystem *GetGlobalLoggingSystem();
  197. #define Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, AppendCallStackLength ) \
  198. do \
  199. { \
  200. CLoggingSystem *pLoggingSystem = GetGlobalLoggingSystem(); \
  201. if ( pLoggingSystem->IsChannelEnabled( Channel, Severity ) ) \
  202. { \
  203. tchar formattedMessage[MAX_LOGGING_MESSAGE_LENGTH]; \
  204. va_list args; \
  205. va_start( args, MessageFormat ); \
  206. Tier0Internal_vsntprintf( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, MessageFormat, args ); \
  207. va_end( args ); \
  208. AppendCallStackToLogMessage( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, AppendCallStackLength ); \
  209. pLoggingSystem->LogDirect( Channel, Severity, Color, formattedMessage ); \
  210. } \
  211. } while( 0 )
  212. #define Log_LegacyHelperColor( Channel, Severity, Color, MessageFormat ) Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, 0 )
  213. #define Log_LegacyHelper_Stack( Channel, Severity, MessageFormat, AppendCallStackLength ) Log_LegacyHelperColor_Stack( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat, AppendCallStackLength )
  214. #define Log_LegacyHelper( Channel, Severity, MessageFormat ) Log_LegacyHelperColor( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat )
  215. #if !defined( DBGFLAG_STRINGS_STRIP )
  216. void Msg( const tchar* pMsgFormat, ... )
  217. {
  218. Log_LegacyHelper( LOG_GENERAL, LS_MESSAGE, pMsgFormat );
  219. }
  220. void Warning( const tchar *pMsgFormat, ... )
  221. {
  222. Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, AutomaticWarningCallStackLength() );
  223. }
  224. void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... )
  225. {
  226. Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, iMaxCallStackLength );
  227. }
  228. #endif // !DBGFLAG_STRINGS_STRIP
  229. void Error( const tchar *pMsgFormat, ... )
  230. {
  231. #if !defined( DBGFLAG_STRINGS_STRIP )
  232. Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, AutomaticErrorCallStackLength() );
  233. // Many places that call Error assume that execution will not continue afterwards so it
  234. // is important to exit here. The function prototype promises that this will happen.
  235. Plat_ExitProcess( 100 );
  236. #endif
  237. }
  238. void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... )
  239. {
  240. #if !defined( DBGFLAG_STRINGS_STRIP )
  241. Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, iMaxCallStackLength );
  242. // Many places that call Error_SpewCallStack assume that execution will not continue afterwards so it
  243. // is important to exit here. The function prototype promises that this will happen.
  244. Plat_ExitProcess( 100 );
  245. #endif
  246. }
  247. #if !defined( DBGFLAG_STRINGS_STRIP )
  248. //-----------------------------------------------------------------------------
  249. // A couple of super-common dynamic spew messages, here for convenience
  250. // These looked at the "developer" group, print if it's level 1 or higher
  251. //-----------------------------------------------------------------------------
  252. void DevMsg( int level, const tchar* pMsgFormat, ... )
  253. {
  254. LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER;
  255. Log_LegacyHelper( channel, LS_MESSAGE, pMsgFormat );
  256. }
  257. void DevWarning( int level, const tchar *pMsgFormat, ... )
  258. {
  259. LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER;
  260. Log_LegacyHelper( channel, LS_WARNING, pMsgFormat );
  261. }
  262. void DevMsg( const tchar *pMsgFormat, ... )
  263. {
  264. Log_LegacyHelper( LOG_DEVELOPER, LS_MESSAGE, pMsgFormat );
  265. }
  266. void DevWarning( const tchar *pMsgFormat, ... )
  267. {
  268. Log_LegacyHelper( LOG_DEVELOPER, LS_WARNING, pMsgFormat );
  269. }
  270. void ConColorMsg( const Color& clr, const tchar* pMsgFormat, ... )
  271. {
  272. Log_LegacyHelperColor( LOG_CONSOLE, LS_MESSAGE, clr, pMsgFormat );
  273. }
  274. void ConMsg( const tchar *pMsgFormat, ... )
  275. {
  276. Log_LegacyHelper( LOG_CONSOLE, LS_MESSAGE, pMsgFormat );
  277. }
  278. void ConDMsg( const tchar *pMsgFormat, ... )
  279. {
  280. Log_LegacyHelper( LOG_DEVELOPER_CONSOLE, LS_MESSAGE, pMsgFormat );
  281. }
  282. #endif // !DBGFLAG_STRINGS_STRIP
  283. // If we don't have a function from math.h, then it doesn't link certain floating-point
  284. // functions in and printfs with %f cause runtime errors in the C libraries.
  285. PLATFORM_INTERFACE float CrackSmokingCompiler( float a )
  286. {
  287. return (float)fabs( a );
  288. }
  289. void* Plat_SimpleLog( const tchar* file, int line )
  290. {
  291. FILE* f = _tfopen( _T("simple.log"), _T("at+") );
  292. _ftprintf( f, _T("%s:%i\n"), file, line );
  293. fclose( f );
  294. return NULL;
  295. }
  296. #if !defined( DBGFLAG_STRINGS_STRIP )
  297. //-----------------------------------------------------------------------------
  298. // Purpose: For debugging startup times, etc.
  299. // Input : *fmt -
  300. // ... -
  301. //-----------------------------------------------------------------------------
  302. void COM_TimestampedLog( char const *fmt, ... )
  303. {
  304. static float s_LastStamp = 0.0;
  305. static bool s_bShouldLog = false;
  306. static bool s_bShouldLogToConsole = false;
  307. static bool s_bShouldLogToETW = false;
  308. static bool s_bChecked = false;
  309. static bool s_bFirstWrite = false;
  310. if ( !s_bChecked )
  311. {
  312. s_bShouldLog = ( CommandLine()->CheckParm( "-profile" ) ) ? true : false;
  313. s_bShouldLogToConsole = ( CommandLine()->ParmValue( "-profile", 0.0f ) != 0.0f ) ? true : false;
  314. s_bShouldLogToETW = ( CommandLine()->CheckParm( "-etwprofile" ) ) ? true : false;
  315. if ( s_bShouldLogToETW )
  316. {
  317. s_bShouldLog = true;
  318. }
  319. s_bChecked = true;
  320. }
  321. if ( !s_bShouldLog )
  322. {
  323. return;
  324. }
  325. char string[1024];
  326. va_list argptr;
  327. va_start( argptr, fmt );
  328. Tier0Internal_vsnprintf( string, sizeof( string ), fmt, argptr );
  329. va_end( argptr );
  330. float curStamp = Plat_FloatTime();
  331. #if defined( _X360 )
  332. XBX_rTimeStampLog( curStamp, string );
  333. #elif defined( _PS3 )
  334. Log_Warning( LOG_LOADING, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
  335. #endif
  336. if ( IsPC() )
  337. {
  338. // If ETW profiling is enabled then do it only.
  339. if ( s_bShouldLogToETW )
  340. {
  341. ETWMark( string );
  342. }
  343. else
  344. {
  345. if ( !s_bFirstWrite )
  346. {
  347. unlink( "timestamped.log" );
  348. s_bFirstWrite = true;
  349. }
  350. FILE* fp = fopen( "timestamped.log", "at+" );
  351. fprintf( fp, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
  352. fclose( fp );
  353. if ( s_bShouldLogToConsole )
  354. {
  355. Msg( "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
  356. }
  357. }
  358. }
  359. s_LastStamp = curStamp;
  360. }
  361. #endif // !DBGFLAG_STRINGS_STRIP
  362. static AssertFailedNotifyFunc_t s_AssertFailedNotifyFunc = NULL;
  363. //-----------------------------------------------------------------------------
  364. // Sets an assert failed notify handler
  365. //-----------------------------------------------------------------------------
  366. void SetAssertFailedNotifyFunc( AssertFailedNotifyFunc_t func )
  367. {
  368. s_AssertFailedNotifyFunc = func;
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Calls the assert failed notify handler if one has been set
  372. //-----------------------------------------------------------------------------
  373. void CallAssertFailedNotifyFunc( const char *pchFile, int nLine, const char *pchMessage )
  374. {
  375. if ( s_AssertFailedNotifyFunc )
  376. s_AssertFailedNotifyFunc( pchFile, nLine, pchMessage );
  377. }
  378. #ifdef IS_WINDOWS_PC
  379. class CHardwareBreakPoint
  380. {
  381. public:
  382. enum EOpCode
  383. {
  384. BRK_SET = 0,
  385. BRK_UNSET,
  386. };
  387. CHardwareBreakPoint()
  388. {
  389. m_eOperation = BRK_SET;
  390. m_pvAddress = 0;
  391. m_hThread = 0;
  392. m_hThreadEvent = 0;
  393. m_nRegister = 0;
  394. m_bSuccess = false;
  395. }
  396. const void *m_pvAddress;
  397. HANDLE m_hThread;
  398. EHardwareBreakpointType m_eType;
  399. EHardwareBreakpointSize m_eSize;
  400. HANDLE m_hThreadEvent;
  401. int m_nRegister;
  402. EOpCode m_eOperation;
  403. bool m_bSuccess;
  404. static void SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue );
  405. static DWORD WINAPI ThreadProc( LPVOID lpParameter );
  406. };
  407. void CHardwareBreakPoint::SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue )
  408. {
  409. DWORD_PTR mask = (1 << bits) - 1;
  410. dw = (dw & ~(mask << lowBit)) | (newValue << lowBit);
  411. }
  412. DWORD WINAPI CHardwareBreakPoint::ThreadProc( LPVOID lpParameter )
  413. {
  414. CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint * >( lpParameter );
  415. SuspendThread( h->m_hThread );
  416. // Get current context
  417. CONTEXT ct = {0};
  418. ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  419. GetThreadContext(h->m_hThread,&ct);
  420. int FlagBit = 0;
  421. bool Dr0Busy = false;
  422. bool Dr1Busy = false;
  423. bool Dr2Busy = false;
  424. bool Dr3Busy = false;
  425. if (ct.Dr7 & 1)
  426. Dr0Busy = true;
  427. if (ct.Dr7 & 4)
  428. Dr1Busy = true;
  429. if (ct.Dr7 & 16)
  430. Dr2Busy = true;
  431. if (ct.Dr7 & 64)
  432. Dr3Busy = true;
  433. if ( h->m_eOperation == CHardwareBreakPoint::BRK_UNSET )
  434. {
  435. // Remove
  436. if (h->m_nRegister == 0)
  437. {
  438. FlagBit = 0;
  439. ct.Dr0 = 0;
  440. Dr0Busy = false;
  441. }
  442. if (h->m_nRegister == 1)
  443. {
  444. FlagBit = 2;
  445. ct.Dr1 = 0;
  446. Dr1Busy = false;
  447. }
  448. if (h->m_nRegister == 2)
  449. {
  450. FlagBit = 4;
  451. ct.Dr2 = 0;
  452. Dr2Busy = false;
  453. }
  454. if (h->m_nRegister == 3)
  455. {
  456. FlagBit = 6;
  457. ct.Dr3 = 0;
  458. Dr3Busy = false;
  459. }
  460. ct.Dr7 &= ~(1 << FlagBit);
  461. }
  462. else
  463. {
  464. if (!Dr0Busy)
  465. {
  466. h->m_nRegister = 0;
  467. ct.Dr0 = (DWORD_PTR)h->m_pvAddress;
  468. Dr0Busy = true;
  469. }
  470. else if (!Dr1Busy)
  471. {
  472. h->m_nRegister = 1;
  473. ct.Dr1 = (DWORD_PTR)h->m_pvAddress;
  474. Dr1Busy = true;
  475. }
  476. else if (!Dr2Busy)
  477. {
  478. h->m_nRegister = 2;
  479. ct.Dr2 = (DWORD_PTR)h->m_pvAddress;
  480. Dr2Busy = true;
  481. }
  482. else if (!Dr3Busy)
  483. {
  484. h->m_nRegister = 3;
  485. ct.Dr3 = (DWORD_PTR)h->m_pvAddress;
  486. Dr3Busy = true;
  487. }
  488. else
  489. {
  490. h->m_bSuccess = false;
  491. ResumeThread(h->m_hThread);
  492. SetEvent(h->m_hThreadEvent);
  493. return 0;
  494. }
  495. ct.Dr6 = 0;
  496. int st = 0;
  497. if (h->m_eType == BREAKPOINT_EXECUTE)
  498. st = 0;
  499. if (h->m_eType == BREAKPOINT_READWRITE)
  500. st = 3;
  501. if (h->m_eType == BREAKPOINT_WRITE)
  502. st = 1;
  503. int le = 0;
  504. if (h->m_eSize == BREAKPOINT_SIZE_1)
  505. le = 0;
  506. if (h->m_eSize == BREAKPOINT_SIZE_2)
  507. le = 1;
  508. if (h->m_eSize == BREAKPOINT_SIZE_4)
  509. le = 3;
  510. if (h->m_eSize == BREAKPOINT_SIZE_8)
  511. le = 2;
  512. SetBits( ct.Dr7, 16 + h->m_nRegister*4, 2, st );
  513. SetBits( ct.Dr7, 18 + h->m_nRegister*4, 2, le );
  514. SetBits( ct.Dr7, h->m_nRegister*2,1,1);
  515. }
  516. ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  517. SetThreadContext(h->m_hThread,&ct);
  518. ResumeThread( h->m_hThread );
  519. h->m_bSuccess = true;
  520. SetEvent( h->m_hThreadEvent );
  521. return 0;
  522. }
  523. HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation )
  524. {
  525. CHardwareBreakPoint *h = new CHardwareBreakPoint();
  526. h->m_pvAddress = pvLocation;
  527. h->m_eSize = eSize;
  528. h->m_eType = eType;
  529. HANDLE hThread = GetCurrentThread();
  530. h->m_hThread = hThread;
  531. if ( hThread == GetCurrentThread() )
  532. {
  533. DWORD nThreadId = GetCurrentThreadId();
  534. h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId );
  535. }
  536. h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  537. h->m_eOperation = CHardwareBreakPoint::BRK_SET; // Set Break
  538. CreateThread( 0, 0, CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0, 0 );
  539. WaitForSingleObject( h->m_hThreadEvent,INFINITE );
  540. CloseHandle( h->m_hThreadEvent );
  541. h->m_hThreadEvent = 0;
  542. if ( hThread == GetCurrentThread() )
  543. {
  544. CloseHandle( h->m_hThread );
  545. }
  546. h->m_hThread = hThread;
  547. if ( !h->m_bSuccess )
  548. {
  549. delete h;
  550. return (HardwareBreakpointHandle_t)0;
  551. }
  552. return (HardwareBreakpointHandle_t)h;
  553. }
  554. bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle )
  555. {
  556. CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint* >( handle );
  557. if ( !h )
  558. {
  559. return false;
  560. }
  561. bool bOpened = false;
  562. if ( h->m_hThread == GetCurrentThread() )
  563. {
  564. DWORD nThreadId = GetCurrentThreadId();
  565. h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId );
  566. bOpened = true;
  567. }
  568. h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  569. h->m_eOperation = CHardwareBreakPoint::BRK_UNSET; // Remove Break
  570. CreateThread( 0,0,CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0,0 );
  571. WaitForSingleObject( h->m_hThreadEvent, INFINITE );
  572. CloseHandle( h->m_hThreadEvent );
  573. h->m_hThreadEvent = 0;
  574. if ( bOpened )
  575. {
  576. CloseHandle( h->m_hThread );
  577. }
  578. delete h;
  579. return true;
  580. }
  581. #endif // IS_WINDOWS_PC