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.

300 lines
12 KiB

  1. #ifndef _CEGCLIENTWRAPPER_H_
  2. #define _CEGCLIENTWRAPPER_H_
  3. #pragma once
  4. #include "xbox/xboxstubs.h" // defines DWORD, DWORD_PTR, etc.
  5. // required by cegclient.h, but no need to pull in all of windef.h
  6. #if defined( PLATFORM_64BITS )
  7. typedef int64 INT_PTR;
  8. #else
  9. typedef int32 INT_PTR;
  10. #endif
  11. typedef unsigned char BYTE;
  12. typedef BYTE *LPBYTE;
  13. typedef int32 INT32;
  14. typedef uint32 DWORD32;
  15. typedef uint64 DWORD64;
  16. #define CEG_GET_CONSTANT_VALUE_AVOID_CEG( fn_name ) fn_name() // makes it easy for us to turn off CEG checks if one of the CEG'ed functions has a bigger impact on perf than expected
  17. // To disable CEG in your build for one or more modules, add "/NO_CEG" to your VPC parameters
  18. #if (!defined( USE_CEG ) || ( !defined( CLIENT_DLL ) && !defined( GAME_DLL ) ) )
  19. #define CEG_NOINLINE
  20. // Stub out functions if CEG is disabled
  21. #define STEAMWORKS_REGISTERTHREAD() (true)
  22. #define STEAMWORKS_UNREGISTERTHREAD() (true)
  23. #define STEAMWORKS_INITCEGLIBRARY() (true)
  24. #define STEAMWORKS_TERMCEGLIBRARY() (true)
  25. #define STEAMWORKS_TESTSECRET()
  26. #define STEAMWORKS_TESTSECRETALWAYS()
  27. #define STEAMWORKS_SELFCHECK()
  28. #define STEAMWORKS_TESTSECRET_AMORTIZE( period )
  29. #define STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( period )
  30. #define STEAMWORKS_SELFCHECK_AMORTIZE( period )
  31. #define RANDOM_CEG_TEST_SECRET()
  32. #define RANDOM_CEG_TEST_SECRET_PERIOD( testPeriod, checkPeriod )
  33. #define RANDOM_CEG_TEST_SECRET_LINE_PERIOD( testPeriod, testLinePeriod, checkPeriod, checkLinePeriod )
  34. #define CEG_PROTECT_FUNCTION( unquotedSymbolHelper )
  35. #define CEG_ENCRYPT_FUNCTION( unquotedSymbolHelper )
  36. #define CEG_PROTECT_MEMBER_FUNCTION( unquotedSymbolHelper )
  37. #define CEG_PROTECT_VIRTUAL_FUNCTION( unquotedSymbolHelper )
  38. #define CEG_PROTECT_STATIC_MEMBER_FUNCTION( unquotedSymbolHelper, fn_name )
  39. #define CEG_DECLARE_CONSTANT_FUNCTION( fn_name ) extern DWORD __cdecl fn_name();
  40. #define CEG_DECLARE_CONSTANT_FLOAT_FUNCTION( fn_name ) extern float __cdecl fn_name();
  41. #define CEG_DEFINE_CONSTANT_FUNCTION( fn_name, val ) DWORD __cdecl fn_name() { return val; }
  42. #define CEG_DEFINE_CONSTANT_FLOAT_FUNCTION( fn_name, val ) float __cdecl fn_name() { return val; }
  43. #define CEG_GET_CONSTANT_VALUE( fn_name ) fn_name()
  44. #define CEG_GCV_PRE()
  45. #define CEG_GCV_POST()
  46. #else // CEG is enabled
  47. #if defined( _GAMECONSOLE ) || defined( POSIX ) || defined( NO_STEAM )
  48. #error
  49. #endif
  50. #include "cegclient.h"
  51. // use this on any functions where we use CEG_PROTECT to ensure they don't get inlined in the CEG build
  52. #define CEG_NOINLINE __declspec(noinline)
  53. // wrapping CEG calls in macros allows us to hide interface changes and centrally add checks and perf instrumentation
  54. #define STEAMWORKS_REGISTERTHREAD() Steamworks_RegisterThread()
  55. #define STEAMWORKS_UNREGISTERTHREAD() Steamworks_UnRegisterThread()
  56. #define STEAMWORKS_INITCEGLIBRARY() Steamworks_InitCEGLibrary()
  57. #define STEAMWORKS_TERMCEGLIBRARY() Steamworks_TermCEGLibrary()
  58. #define CEG_DECLARE_CONSTANT_FUNCTION( fn_name ) CEG_Declare_Constant_Function( fn_name )
  59. #define CEG_DECLARE_CONSTANT_FLOAT_FUNCTION( fn_name ) CEG_Declare_ConstantFloat_Function( fn_name )
  60. #define CEG_DEFINE_CONSTANT_FUNCTION( fn_name, val ) CEG_Define_Constant_Function( fn_name, val )
  61. #define CEG_DEFINE_CONSTANT_FLOAT_FUNCTION( fn_name, val ) CEG_Define_ConstantFloat_Function2( fn_name, val )
  62. #define CEG_GET_CONSTANT_VALUE( fn_name ) CEG_GetConstantValue( fn_name )
  63. // seeded with large primes at frequencies that lead to approximately one check every 30 seconds
  64. #define RANDOM_CEG_TEST_SECRET() \
  65. RANDOM_CEG_TEST_SECRET_LINE_PERIOD( 128449, 19, 1102441, 397 )
  66. #define RANDOM_CEG_TEST_SECRET_PERIOD( testPeriod, checkPeriod ) \
  67. RANDOM_CEG_TEST_SECRET_LINE_PERIOD( testPeriod, 0, checkPeriod, 0 )
  68. // uncomment here to enable dev messages per CEG call, including CEG performance numbers
  69. //#define PROFILE_CEG
  70. #if !defined( PROFILE_CEG )
  71. #define CEG_PROFILE_DECL
  72. #define CEG_PROFILE_BLOCK( fn_name, fn_type, identifier ) fn_name;
  73. #define CEG_GCV_PRE()
  74. #define CEG_GCV_POST()
  75. #else // defined( PROFILE_CEG )
  76. #include "tier0\fasttimer.h"
  77. extern CAverageCycleCounter allCEG;
  78. extern CAverageCycleCounter allTestSecret;
  79. extern CAverageCycleCounter allSelfCheck;
  80. extern CAverageCycleCounter allProtectMember;
  81. extern CAverageCycleCounter allProtectVirtual;
  82. #if !defined( MEMOVERRIDE_MODULE )
  83. #define MEMOVERRIDE_MODULE UNKNOWN_MODULE
  84. #endif
  85. #define _MKSTRING(arg) #arg
  86. #define MKSTRING(arg) _MKSTRING(arg)
  87. #define CEG_PROFILE_BLOCK( fn_name, fn_type, identifier ) \
  88. static unsigned long s_##fn_type##Hits = 0; \
  89. s_##fn_type##Hits++; \
  90. static CAverageCycleCounter this##fn_type; \
  91. { \
  92. CAverageTimeMarker this##fn_type##Marker( &this##fn_type ); \
  93. CAverageTimeMarker all##fn_type##Marker( &all##fn_type ); \
  94. CAverageTimeMarker allCEGMarker( &allCEG ); \
  95. fn_name; \
  96. } \
  97. DevMsg( "%s: %s%s %s:%d - %.2fms avg (%.2fms total, %.2fms peak, %d iters), %lu/%lu = %.5f%% hit rate.\n" \
  98. "Avg CEG %s Cost: %.2fms Avg CEG Cost: %.2fms\n", \
  99. MKSTRING(MEMOVERRIDE_MODULE), identifier, #fn_type, __FILE__, __LINE__, \
  100. this##fn_type.GetAverageMilliseconds(), this##fn_type.GetTotalMilliseconds(), this##fn_type.GetPeakMilliseconds(), this##fn_type.GetIters(), \
  101. s_##fn_type##Hits, s_tests, \
  102. float( s_##fn_type##Hits * 100 ) / float( s_tests ), \
  103. #fn_type, \
  104. all##fn_type.GetAverageMilliseconds(), \
  105. allCEG.GetAverageMilliseconds() );
  106. #define CEG_PROFILE_DECL \
  107. static unsigned long int s_tests = 0; \
  108. s_tests++;
  109. #define CEG_GCV_PRE() \
  110. CFastTimer __FUNCTION__##Timer; \
  111. __FUNCTION__##Timer.Start();
  112. #define CEG_GCV_POST() \
  113. __FUNCTION__##Timer.End(); \
  114. if( __FUNCTION__##Timer.GetDuration().GetMillisecondsF() > 0.5f ) \
  115. { \
  116. DevMsg( "%s: GetConstantValue in %s : %.2fms\n", \
  117. MKSTRING(MEMOVERRIDE_MODULE), __FUNCTION__, __FUNCTION__##Timer.GetDuration().GetMillisecondsF() ); \
  118. }
  119. #endif // PROFILE_CEG off/on
  120. // the below macros allow us to turn profiling on or off with a single #ifdef, using the same underlying implementation in each case
  121. #define RANDOM_CEG_TEST_SECRET_LINE_PERIOD( testPeriod, testLinePeriod, checkPeriod, checkLinePeriod ) \
  122. do { \
  123. const unsigned long tp = testPeriod + testLinePeriod * __LINE__; \
  124. const unsigned long cp = checkPeriod + checkLinePeriod * __LINE__; \
  125. static unsigned long s_nCegCounter = __LINE__ ^ __COUNTER__ ^ reinterpret_cast<int>( &s_nCegCounter ); \
  126. ++s_nCegCounter; \
  127. CEG_PROFILE_DECL; \
  128. if ( !( ( s_nCegCounter ) % ( tp ) ) ) \
  129. { \
  130. CEG_PROFILE_BLOCK( Steamworks_TestSecretAlways(), TestSecret, "Random " ); \
  131. } \
  132. else if ( !( ( s_nCegCounter ) % ( cp ) ) ) \
  133. { \
  134. CEG_PROFILE_BLOCK( Steamworks_SelfCheck(), SelfCheck, "Random " ); \
  135. } \
  136. } \
  137. while( 0 );
  138. //
  139. // Can't grab metrics - although this is placed within the scope a function -
  140. // The effect is to change calls to the function to first execute some CEG code,
  141. // and this CEG code is not available within this scope.
  142. // The CEG code computes the address of the containing function, and jumps to it.
  143. //
  144. #define CEG_PROTECT_FUNCTION( unquotedSymbolHelper ) \
  145. CEG_ProtectFunction( );
  146. //
  147. // Can't grab metrics - although this is placed within the scope a function -
  148. // The effect is to change calls to the function to first execute some CEG code,
  149. // and this CEG code is not available within this scope.
  150. //
  151. // The body of the function that contains this macro is encrypted, and the CEG code
  152. // decrypts the opcodes and places them in executable memory, and then executes it.
  153. // Upon return, the executable memory is released.
  154. //
  155. #define CEG_ENCRYPT_FUNCTION( unquotedSymbolHelper ) \
  156. CEG_EncryptFunction( );
  157. #define CEG_PROTECT_MEMBER_FUNCTION( unquotedSymbolHelper ) \
  158. do { \
  159. CEG_PROFILE_DECL; \
  160. CEG_PROFILE_BLOCK( CEG_ProtectFunction( ), ProtectMember, "" ); \
  161. } \
  162. while( 0 );
  163. #define CEG_PROTECT_VIRTUAL_FUNCTION( unquotedSymbolHelper ) \
  164. do { \
  165. CEG_PROFILE_DECL; \
  166. CEG_PROFILE_BLOCK( CEG_ProtectFunction( ), ProtectVirtual, "" ); \
  167. } while( 0 );
  168. // defined outside the scope of a function, so can't trivially grab metrics
  169. #define CEG_PROTECT_STATIC_MEMBER_FUNCTION( unquotedSymbolHelper, fn_name ) \
  170. CEG_Protect_StaticMemberFunction( unquotedSymbolHelper, fn_name );
  171. #define STEAMWORKS_TESTSECRET() \
  172. do { \
  173. CEG_PROFILE_DECL; \
  174. CEG_PROFILE_BLOCK( Steamworks_TestSecret(), TestSecret, "" ); \
  175. } while( 0 );
  176. #define STEAMWORKS_TESTSECRETALWAYS() \
  177. do { \
  178. CEG_PROFILE_DECL; \
  179. CEG_PROFILE_BLOCK( Steamworks_TestSecretAlways(), TestSecret, "" ); \
  180. } while( 0 );
  181. #define STEAMWORKS_SELFCHECK() \
  182. do { \
  183. CEG_PROFILE_DECL; \
  184. CEG_PROFILE_BLOCK( Steamworks_SelfCheck(), SelfCheck, "" ); \
  185. } while( 0 );
  186. // AMORTIZED
  187. #define STEAMWORKS_TESTSECRET_AMORTIZE( period ) \
  188. do { \
  189. const unsigned long tp = period; \
  190. static unsigned long s_nCegCounter = __LINE__ ^ __COUNTER__ ^ reinterpret_cast<int>( &s_nCegCounter ); \
  191. ++s_nCegCounter; \
  192. CEG_PROFILE_DECL; \
  193. if ( !( ( s_nCegCounter ) % ( tp ) ) ) \
  194. { \
  195. CEG_PROFILE_BLOCK( Steamworks_TestSecret(), TestSecret, "Amortized " ); \
  196. } \
  197. } while( 0 );
  198. #define STEAMWORKS_TESTSECRETALWAYS_AMORTIZE( period ) \
  199. do { \
  200. const unsigned long tp = period; \
  201. static unsigned long s_nCegCounter = __LINE__ ^ __COUNTER__ ^ reinterpret_cast<int>( &s_nCegCounter ); \
  202. ++s_nCegCounter; \
  203. CEG_PROFILE_DECL; \
  204. if ( !( ( s_nCegCounter ) % ( tp ) ) ) \
  205. { \
  206. CEG_PROFILE_BLOCK( Steamworks_TestSecretAlways(), TestSecret, "Amortized " ); \
  207. } \
  208. } while( 0 );
  209. #define STEAMWORKS_SELFCHECK_AMORTIZE( period ) \
  210. do { \
  211. const unsigned long tp = period; \
  212. static unsigned long s_nCegCounter = __LINE__ ^ __COUNTER__ ^ reinterpret_cast<int>( &s_nCegCounter ); \
  213. ++s_nCegCounter; \
  214. CEG_PROFILE_DECL; \
  215. if ( !( ( s_nCegCounter ) % ( tp ) ) ) \
  216. { \
  217. CEG_PROFILE_BLOCK( Steamworks_SelfCheck(), TestSecret, "Amortized " ); \
  218. } \
  219. } while( 0 );
  220. #endif // CEG disabled/enabled
  221. #if defined( CLIENT_DLL ) // client-only
  222. void Init_GCVs();
  223. CEG_DECLARE_CONSTANT_FUNCTION( HudAllowTextChatFlag );
  224. CEG_DECLARE_CONSTANT_FUNCTION( HudAllowBuyMenuFlag );
  225. CEG_DECLARE_CONSTANT_FUNCTION( UiAllowProperTintFlag );
  226. #elif defined( GAME_DLL ) // server-only
  227. void Init_GCVs();
  228. #endif // defined( GAME_DLL )
  229. // Worst-case, if you need to debug CEG calls or CEG perf, and CEG profiling isn't doing the trick (it doesn't cover everything), you can
  230. // do a binary search on one or all of the below calls by restoring part of the #if 0 block below. You'll get a duplicate definition warning,
  231. // but anything redefined below will be a no-op in the build, allowing you to rule it out as a potential perf issue.
  232. // Remember that CEG builds neeed to be rebuilds (CEG'ed dlls only), but the /MP flag should make it about 60 seconds per rebuild.
  233. #if 0
  234. #define STEAMWORKS_TESTSECRET()
  235. #define STEAMWORKS_TESTSECRETALWAYS()
  236. #define STEAMWORKS_SELFCHECK()
  237. #define RANDOM_CEG_TEST_SECRET()
  238. #define RANDOM_CEG_TEST_SECRET_PERIOD( testPeriod, checkPeriod )
  239. #define RANDOM_CEG_TEST_SECRET_LINE_PERIOD( testPeriod, testLinePeriod, checkPeriod, checkLinePeriod )
  240. #define CEG_PROTECT_FUNCTION( unquotedSymbolHelper )
  241. #define CEG_PROTECT_MEMBER_FUNCTION( unquotedSymbolHelper )
  242. #define CEG_PROTECT_VIRTUAL_FUNCTION( unquotedSymbolHelper )
  243. #define CEG_PROTECT_STATIC_MEMBER_FUNCTION( unquotedSymbolHelper, fn_name )
  244. #define CEG_DECLARE_CONSTANT_FUNCTION( fn_name ) extern DWORD __cdecl fn_name();
  245. #define CEG_DECLARE_CONSTANT_FLOAT_FUNCTION( fn_name ) extern float __cdecl fn_name();
  246. #define CEG_DEFINE_CONSTANT_FUNCTION( fn_name, val ) DWORD __cdecl fn_name() { return val; }
  247. #define CEG_DEFINE_CONSTANT_FLOAT_FUNCTION( fn_name, val ) float __cdecl fn_name() { return val; }
  248. #define CEG_GET_CONSTANT_VALUE( fn_name ) fn_name()
  249. #endif
  250. #endif //_CEGCLIENTWRAPPER_H_