|
|
//========= Copyright (c), Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "stdafx.h"
#include "gcsystemaccess.h"
#include "gcjob.h"
#include "gcsdk/gcreportprinter.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
namespace GCSDK {
static GCConVar gcaccess_enable( "gcaccess_enable", "1", "Kill switch that disables all gcaccess tracking and systems" );
DECLARE_GC_EMIT_GROUP( g_EGAccess, access );
//-----------------------------------------------------------------------------------------------------------------------------------------
GCAccessSystem_t GenerateUniqueGCAccessID() { static GCAccessSystem_t s_nID = 0; return s_nID++; }
//-----------------------------------------------------------------------------------------------------------------------------------------
// CGCAccessSystem
//-----------------------------------------------------------------------------------------------------------------------------------------
//a GCAccess system that has been registered
class CGCAccessSystem { public: //the name of the system for display
CUtlString m_sName; //the unique ID for this system
GCAccessSystem_t m_nID; //which actions should be enabled or disabled for this system in particular
uint32 m_nActions; uint32 m_nSuppressActions;
struct AccessStats_t { AccessStats_t(); void Add( const AccessStats_t& rhs ); //how many raw accesses have we had?
uint32 m_nNumValid; //how many failed because the context didn't have rights?
uint32 m_nNumFail; //how many failed because the associated ID wasn't valid?
uint32 m_nNumFailID; };
struct TrackedJob_t { CUtlString m_sContext; AccessStats_t m_Stats; };
//which jobs have violated this system access rights
CUtlHashMapLarge< uintp, TrackedJob_t > m_Jobs; };
//-----------------------------------------------------------------------------------------------------------------------------------------
// CGCAccessContext
//-----------------------------------------------------------------------------------------------------------------------------------------
CGCAccessContext::CGCAccessContext() : m_nActions( 0 ), m_nSuppressActions( 0 ) { }
void CGCAccessContext::Init( const char* pszName, uint32 nActions, uint32 nSuppressActions ) { m_sName = pszName; m_nActions = nActions; m_nSuppressActions = nSuppressActions; }
void CGCAccessContext::AddSystem( GCAccessSystem_t nSystem ) { m_nSystems.InsertIfNotFound( nSystem ); }
bool CGCAccessContext::HasSystem( GCAccessSystem_t system ) const { return ( m_nSystems.Find( system ) != m_nSystems.InvalidIndex() ); }
bool CGCAccessContext::IsSubsetOf( const CGCAccessContext& context ) const { FOR_EACH_VEC( m_nSystems, nCurrSystem ) { if( !context.HasSystem( m_nSystems[ nCurrSystem ] ) ) return false; } return true; }
void CGCAccessContext::AddSystemsFrom( const CGCAccessContext& context ) { FOR_EACH_VEC( context.m_nSystems, nCurrSystem ) { AddSystem( context.m_nSystems[ nCurrSystem ] ); } }
void CGCAccessContext::SetAction( EGCAccessAction eAction, bool bSet ) { if( bSet ) m_nActions |= eAction; else m_nActions &= ~( uint32 )eAction; }
void CGCAccessContext::SetSuppressAction( EGCAccessAction eAction, bool bSet ) { if( bSet ) m_nSuppressActions |= eAction; else m_nSuppressActions &= ~( uint32 )eAction; }
//-----------------------------------------------------------------------------------------------------------------------------------------
// CGCAccess
//-----------------------------------------------------------------------------------------------------------------------------------------
static CGCAccess g_GCAccess; CGCAccess& GGCAccess() { return g_GCAccess; }
CGCAccessSystem::AccessStats_t::AccessStats_t() : m_nNumFail( 0 ) , m_nNumFailID( 0 ) , m_nNumValid( 0 ) {}
void CGCAccessSystem::AccessStats_t::Add( const AccessStats_t& rhs ) { m_nNumFail += rhs.m_nNumFail; m_nNumFailID += rhs.m_nNumFailID; m_nNumValid += rhs.m_nNumValid; }
CGCAccess::CGCAccess() : m_nActions( GCAccessAction_TrackSuccess | GCAccessAction_TrackFail| GCAccessAction_ReturnFail ), m_nSuppressActions( 0 ) { m_GlobalContext.Init( "Global" ); }
void CGCAccess::RegisterSystem( const char* pszName, GCAccessSystem_t nID, uint32 nActions, uint32 nSupressActions ) { //make sure that we don't have a conflict
int nIndex = m_Systems.Find( nID ); if( nIndex != m_Systems.InvalidIndex() ) { // !FIXME!
// DOTAMERGE AssertMsg varargs
AssertMsg3( false, "Multiple systems conflciting in Register System: ID %d, original: %s, new %s", nID, m_Systems[ nIndex ]->m_sName.String(), pszName ); return; }
CGCAccessSystem* pSystem = new CGCAccessSystem; pSystem->m_sName = pszName; pSystem->m_nID = nID; pSystem->m_nActions = nActions; pSystem->m_nSuppressActions = nSupressActions; m_Systems.Insert( nID, pSystem ); }
bool CGCAccess::ValidateAccess( GCAccessSystem_t nSystem ) { //global kill switch
if( !gcaccess_enable.GetBool() ) return true;
return InternalValidateAccess( nSystem, CSteamID(), CSteamID() ); }
bool CGCAccess::ValidateSteamIDAccess( GCAccessSystem_t nSystem, CSteamID steamID ) { //global kill switch
if( !gcaccess_enable.GetBool() ) return true;
CSteamID expectedID = ( g_pJobCur ) ? g_pJobCur->SOVALIDATE_GetSteamID() : steamID; return InternalValidateAccess( nSystem, steamID, expectedID ); }
bool CGCAccess::InternalValidateAccess( GCAccessSystem_t nSystem, CSteamID steamID, CSteamID expectedID ) { //see if tracking for this system is disabled. This list is almost always empty, so just use a linear search for now.
FOR_EACH_VEC( m_SuppressAccess, nAction ) { if( m_SuppressAccess[ nAction ].m_nSystem == nSystem ) return true; }
//assume the global context
const CGCAccessContext* pContext = &m_GlobalContext; const char* pszJobName = "[global]";
//if we have a job, use it's context
if( g_pJobCur ) { const CGCJob* pJob = static_cast< const CGCJob* >( g_pJobCur ); pszJobName = pJob->GetName(); if( pJob->GetContext() ) pContext = pJob->GetContext(); }
//is this a valid system to access
bool bValidSteamID = ( steamID == expectedID ); bool bValidSystem = pContext->HasSystem( nSystem ); bool bValidAccess = ( bValidSystem && bValidSteamID );
//determine the actions we want to do for tracking
uint32 nActions = pContext->GetActions() | m_nActions; uint32 nSuppressActions = pContext->GetSuppressActions() | m_nSuppressActions;
//look up the system that we are accessing
CGCAccessSystem* pSystem = NULL; int nSystemIndex = m_Systems.Find( nSystem ); if( nSystemIndex == m_Systems.InvalidIndex() ) { // !FIXME! DOTAMERGE
// AssertMsg varargs
AssertMsg1( false, "Error: Tracking a system that has not been registered. Make sure to register system %u", nSystem ); } else { //make sure that we have a stat entry for this job
pSystem = m_Systems[ nSystemIndex ]; nActions |= pSystem->m_nActions; nSuppressActions |= pSystem->m_nSuppressActions; }
//remove any suppressed actions
nActions &= ~nSuppressActions;
//see if we need to track this access
bool bTrackSuccess = ( nActions & GCAccessAction_TrackSuccess ) && bValidAccess; bool bTrackFail = ( nActions & GCAccessAction_TrackFail ) && !bValidAccess; if( ( bTrackSuccess || bTrackFail ) && pSystem ) { //make sure that we have a stat entry for this job
int nJobIndex = pSystem->m_Jobs.Find( ( uintp )pszJobName ); if( nJobIndex == pSystem->m_Jobs.InvalidIndex() ) { nJobIndex = pSystem->m_Jobs.Insert( ( uintp )pszJobName ); pSystem->m_Jobs[ nJobIndex ].m_sContext = pContext->GetName(); } //update our stats based upon what was valid and what wasn't
CGCAccessSystem::AccessStats_t& stats = pSystem->m_Jobs[ nJobIndex ].m_Stats; if( bTrackSuccess ) stats.m_nNumValid++;
if( bTrackFail ) { if( !bValidSteamID ) stats.m_nNumFailID++; if( !bValidSystem ) stats.m_nNumFail++; } }
//see if this is a single access we want to try and track
FOR_EACH_VEC( m_SingleAsserts, nCurrAssert ) { SingleAssert_t* pAssert = m_SingleAsserts[ nCurrAssert ]; if( nSystem == pAssert->m_System ) { if( V_stricmp( ( pAssert->m_bContext ) ? pContext->GetName() : pszJobName, pAssert->m_sContextOrJob ) == 0 ) { //log this assert
{ // !FIXME! DOTAMERGE
//CGCInterface::CDisableAssertRateLimit disableAssertLimit;
// !FIXME! DOTAMERGE
// AssertMsg varargs
AssertMsg3( false, "GCSystemAccess Caught %s (context %s) calling into %s", pszJobName, pContext->GetName(), pSystem ? pSystem->m_sName.String() : "unknown" ); }
//and clear it
delete pAssert; m_SingleAsserts.FastRemove( nCurrAssert ); } } }
//at this point, if it is a valid access, just bail
if( bValidAccess ) return true;
//otherwise, handle the failure case
if( nActions & ( GCAccessAction_Msg | GCAccessAction_Assert ) ) { int nSystemIndex = m_Systems.Find( nSystem ); const char* pszSystem = ( nSystemIndex != m_Systems.InvalidIndex() ) ? m_Systems[ nSystemIndex ]->m_sName.String() : "<unregistered>";
//display a message based upon if it was a system or ID violation
CFmtStr1024 szMsg; if( !bValidSystem ) { szMsg.sprintf( "Job %s Accessed invalid system %s (%u) while in context %s\n", pszJobName, pszSystem, nSystem, pContext->GetName() ); } else { szMsg.sprintf( "Job %s Accessed invalid steam ID %s but expected %s in system %s (%u) while in context %s\n", pszJobName, steamID.RenderLink(), expectedID.RenderLink(), pszSystem, nSystem, pContext->GetName() ); }
if( nActions & GCAccessAction_Msg ) EG_MSG( g_EGAccess, "%s", szMsg.String() ); if( nActions & GCAccessAction_Assert ) { // !FIXME! DOTAMERGE
// AssertMsg varargs
AssertMsg1( false, "%s", szMsg.String() ); } }
return !( nActions & GCAccessAction_ReturnFail ); }
void CGCAccess::SuppressAccess( GCAccessSystem_t nSystem, bool bEnable ) { //see if it is an existing item already suppressed that we need to modify the ref count of
FOR_EACH_VEC( m_SuppressAccess, nAccess ) { if( m_SuppressAccess[ nAccess ].m_nSystem == nSystem ) { if( bEnable ) { //to enable, we want to decrease the disable count, or remove if we are fully re-enabled
if( m_SuppressAccess[ nAccess ].m_nCount <= 1 ) m_SuppressAccess.FastRemove( nAccess ); else m_SuppressAccess[ nAccess ].m_nCount--; } else { m_SuppressAccess[ nAccess ].m_nCount++; } return; } }
//only add it to the list if we are disabling
if( !bEnable ) { SuppressAccess_t access; access.m_nSystem = nSystem; access.m_nCount = 1; m_SuppressAccess.AddToTail( access ); } }
void CGCAccess::ClearSystemStats() { FOR_EACH_MAP_FAST( m_Systems, nSystem ) { m_Systems[ nSystem ]->m_Jobs.Purge(); } }
bool CGCAccess::CatchSingleAssert( const char* pszSystem, bool bContext, const char* pszContextOrJob ) { //find the system we are referencing so we don't add invalid breakpoints if we can avoid it
GCAccessSystem_t nSystemID = ( GCAccessSystem_t )-1; FOR_EACH_MAP_FAST( m_Systems, nSystem ) { if( V_stricmp( m_Systems[ nSystem ]->m_sName, pszSystem ) == 0 ) { nSystemID = m_Systems.Key( nSystem ); break; } }
if( nSystemID == ( GCAccessSystem_t )-1 ) return false;
SingleAssert_t* pAssert = new SingleAssert_t; pAssert->m_System = nSystemID; pAssert->m_bContext = bContext; pAssert->m_sContextOrJob = pszContextOrJob; m_SingleAsserts.AddToTail( pAssert ); return true; }
void CGCAccess::ClearSingleAsserts() { m_SingleAsserts.PurgeAndDeleteElements(); }
//given a display type and a stats object, determines if it meets the criteria
static bool ShouldDisplayStats( CGCAccess::EDisplay eDisplay, const CGCAccessSystem::AccessStats_t& stats ) { if( eDisplay == CGCAccess::eDisplay_Referenced ) return ( stats.m_nNumFail + stats.m_nNumFailID + stats.m_nNumValid ) > 0; if( eDisplay == CGCAccess::eDisplay_Violations ) return ( stats.m_nNumFail + stats.m_nNumFailID ) > 0; if( eDisplay == CGCAccess::eDisplay_IDViolations ) return stats.m_nNumFailID > 0;
//unknown, so just assume all
return true; }
void CGCAccess::ReportJobs( const char* pszContext, EDisplay eDisplay ) const { //collect all of the job stats into a single summary table
CUtlHashMapLarge< uintp, CGCAccessSystem::TrackedJob_t > jobs; FOR_EACH_MAP_FAST( m_Systems, nSystem ) { const CGCAccessSystem* pSystem = m_Systems[ nSystem ]; FOR_EACH_MAP_FAST( pSystem->m_Jobs, nJob ) { const CGCAccessSystem::TrackedJob_t& job = pSystem->m_Jobs[ nJob ]; //skip any contexts we don't care about
if( pszContext && ( V_stricmp( pszContext, job.m_sContext ) != 0 ) ) continue; if( !ShouldDisplayStats( eDisplay, job.m_Stats ) ) continue;
int nIndex = jobs.Find( pSystem->m_Jobs.Key( nJob ) ); if( nIndex == jobs.InvalidIndex() ) { nIndex = jobs.Insert( pSystem->m_Jobs.Key( nJob ) ); jobs[ nIndex ].m_sContext = job.m_sContext; }
jobs[ nIndex ].m_Stats.Add( job.m_Stats ); } }
CGCReportPrinter rp; rp.AddStringColumn( "Job" ); rp.AddStringColumn( "Context" ); rp.AddIntColumn( "Valid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "Invalid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "InvalidID", CGCReportPrinter::eSummary_Total );
FOR_EACH_MAP_FAST( jobs, nJob ) { rp.StrValue( ( const char* )jobs.Key( nJob ), CFmtStr( "gcaccess_dump_job \"%s\" %d", ( const char* )jobs.Key( nJob ), eDisplay ).String() ); rp.StrValue( jobs[ nJob ].m_sContext, CFmtStr( "gcaccess_dump_context \"%s\" %d", jobs[ nJob ].m_sContext.String(), eDisplay ).String() ); rp.IntValue( jobs[ nJob ].m_Stats.m_nNumValid ); rp.IntValue( jobs[ nJob ].m_Stats.m_nNumFail ); rp.IntValue( jobs[ nJob ].m_Stats.m_nNumFailID ); rp.CommitRow(); }
rp.SortReport( "Job", false ); rp.PrintReport( SPEW_CONSOLE ); }
void CGCAccess::ReportSystems( const char* pszContext, EDisplay eDisplay ) const { CGCReportPrinter rp; rp.AddStringColumn( "System" ); rp.AddIntColumn( "ID", CGCReportPrinter::eSummary_None ); rp.AddIntColumn( "Jobs", CGCReportPrinter::eSummary_None ); rp.AddIntColumn( "Valid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "Invalid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "InvalidID", CGCReportPrinter::eSummary_Total );
FOR_EACH_MAP_FAST( m_Systems, nSystem ) { const CGCAccessSystem* pSystem = m_Systems[ nSystem ]; CGCAccessSystem::AccessStats_t stats; FOR_EACH_MAP_FAST( pSystem->m_Jobs, nJob ) { const CGCAccessSystem::TrackedJob_t& job = pSystem->m_Jobs[ nJob ]; //skip any contexts we don't care about
if( pszContext && ( V_stricmp( pszContext, job.m_sContext ) != 0 ) ) continue;
stats.Add( job.m_Stats ); }
if( !ShouldDisplayStats( eDisplay, stats ) ) continue;
rp.StrValue( pSystem->m_sName, CFmtStr( "gcaccess_dump_system \"%s\" %d", pSystem->m_sName.String(), eDisplay ).String() ); rp.IntValue( pSystem->m_nID ); rp.IntValue( pSystem->m_Jobs.Count() ); rp.IntValue( stats.m_nNumValid ); rp.IntValue( stats.m_nNumFail ); rp.IntValue( stats.m_nNumFailID ); rp.CommitRow(); }
rp.SortReport( "System", false ); rp.PrintReport( SPEW_CONSOLE ); }
void CGCAccess::FullReport( const char* pszSystemFilter, const char* pszContextFilter, const char* pszJobFilter, EDisplay eDisplay ) const { CGCReportPrinter rp; rp.AddStringColumn( "Job" ); rp.AddStringColumn( "Context" ); rp.AddStringColumn( "System" ); rp.AddIntColumn( "Valid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "Invalid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "InvalidID", CGCReportPrinter::eSummary_Total );
FOR_EACH_MAP_FAST( m_Systems, nSystem ) { const CGCAccessSystem* pSystem = m_Systems[ nSystem ]; if( pszSystemFilter && V_stricmp( pszSystemFilter, pSystem->m_sName ) ) continue;
FOR_EACH_MAP_FAST( pSystem->m_Jobs, nJob ) { const CGCAccessSystem::AccessStats_t& stats = pSystem->m_Jobs[ nJob ].m_Stats; const char* pszJob = ( const char* )pSystem->m_Jobs.Key( nJob ); const char* pszContext = ( const char* )pSystem->m_Jobs[ nJob ].m_sContext;
if( !ShouldDisplayStats( eDisplay, stats ) ) continue; if( pszJobFilter && V_stricmp( pszJobFilter, pszJob ) ) continue; if( pszContextFilter && V_stricmp( pszContextFilter, pszContext ) ) continue;
rp.StrValue( pszJob, CFmtStr( "gcaccess_dump_job \"%s\" %d", pszJob, eDisplay ).String() ); rp.StrValue( pszContext, CFmtStr( "gcaccess_dump_context \"%s\" %d", pszContext, eDisplay ).String() ); rp.StrValue( pSystem->m_sName, CFmtStr( "gcaccess_dump_system \"%s\" %d", pSystem->m_sName.String(), eDisplay ).String() ); rp.IntValue( stats.m_nNumValid ); rp.IntValue( stats.m_nNumFail ); rp.IntValue( stats.m_nNumFailID ); rp.CommitRow(); } }
rp.SortReport( "Context", false ); rp.PrintReport( SPEW_CONSOLE ); }
void CGCAccess::DependencyReport( const char* pszSystem, EDisplay eDisplay ) const { //first off, we need to find the system we are scanning for dependencies on
const CGCAccessSystem* pMatchSystem = NULL; FOR_EACH_MAP_FAST( m_Systems, nSystem ) { const CGCAccessSystem* pSystem = m_Systems[ nSystem ]; if( V_stricmp( pszSystem, pSystem->m_sName ) == 0 ) { pMatchSystem = pSystem; break; } }
if( !pMatchSystem ) { EG_MSG( SPEW_CONSOLE, "Unable to find system %s for dependency report\n", pszSystem ); return; }
//now generate our report
CGCReportPrinter rp; rp.AddStringColumn( "Job" ); rp.AddStringColumn( "Context" ); rp.AddStringColumn( "System" ); rp.AddIntColumn( "Valid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "Invalid", CGCReportPrinter::eSummary_Total ); rp.AddIntColumn( "InvalidID", CGCReportPrinter::eSummary_Total );
FOR_EACH_MAP_FAST( m_Systems, nSystem ) { const CGCAccessSystem* pSystem = m_Systems[ nSystem ]; //skip ourself
if( pSystem == pMatchSystem ) continue;
FOR_EACH_MAP_FAST( pSystem->m_Jobs, nJob ) { const CGCAccessSystem::AccessStats_t& stats = pSystem->m_Jobs[ nJob ].m_Stats; const char* pszJob = ( const char* )pSystem->m_Jobs.Key( nJob ); const char* pszContext = ( const char* )pSystem->m_Jobs[ nJob ].m_sContext;
//skip any job that isn't using our match system
if( !pMatchSystem->m_Jobs.HasElement( ( uintp )pszJob ) ) continue; if( !ShouldDisplayStats( eDisplay, stats ) ) continue;
rp.StrValue( pszJob, CFmtStr( "gcaccess_dump_job \"%s\" %d", pszJob, eDisplay ).String() ); rp.StrValue( pszContext, CFmtStr( "gcaccess_dump_context \"%s\" %d", pszContext, eDisplay ).String() ); rp.StrValue( pSystem->m_sName, CFmtStr( "gcaccess_dump_system \"%s\" %d", pSystem->m_sName.String(), eDisplay ).String() ); rp.IntValue( stats.m_nNumValid ); rp.IntValue( stats.m_nNumFail ); rp.IntValue( stats.m_nNumFailID ); rp.CommitRow(); } }
rp.SortReport( "System", false ); rp.PrintReport( SPEW_CONSOLE );
}
GC_CON_COMMAND_PARAMS( gcaccess_dump_job, 1, "<Job Name> Dumps all of the accesses associated with the specified job" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().FullReport( NULL, NULL, args[ 1 ], eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_dump_context, 1, "<Job Name> Dumps all of the accesses associated with the specified context" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().FullReport( NULL, args[ 1 ], NULL, eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_dump_system, 1, "<Job Name> Dumps all of the accesses associated with the specified system" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().FullReport( args[ 1 ], NULL, NULL, eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_dump_context_jobs, 1, "<Context Name> Dumps all of the accesses associated with the specified context" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().ReportJobs( args[ 1 ], eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_dump_context_systems, 1, "<Context Name> Dumps all of the accesses associated with the specified context" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().ReportSystems( args[ 1 ], eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_dump_system_dependencies, 1, "<System Name> This will dump out for all jobs that reference the specified system, what other systems they reference" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 3 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 2 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().DependencyReport( args[ 1 ], eDisplay ); }
GC_CON_COMMAND( gcaccess_dump_jobs, "Dumps all the jobs that have been tracked with the gcaccess system as well as count of violations" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 2 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 1 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().ReportJobs( NULL, eDisplay); }
GC_CON_COMMAND( gcaccess_dump_systems, "Dumps all the systems that have been tracked with the gcaccess system as well as count of violations" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 2 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 1 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().ReportSystems( NULL, eDisplay ); }
GC_CON_COMMAND( gcaccess_dump_full, "Dumps all the information tracked by the gcaccess" ) { CGCAccess::EDisplay eDisplay = ( args.ArgC() >= 2 ) ? ( CGCAccess::EDisplay )V_atoi( args[ 1 ] ) : CGCAccess::eDisplay_Referenced; GGCAccess().FullReport( NULL, NULL, NULL, eDisplay ); }
GC_CON_COMMAND_PARAMS( gcaccess_catch_context, 2, "<system> <context> - Catches and generates an assert when the specified context calls into the provided system. This will only generate a single assert" ) { if( !GGCAccess().CatchSingleAssert( args[ 1 ], true, args[ 2 ] ) ) EG_MSG( SPEW_CONSOLE, "Unable to register catch, likely \'%s\' is not a valid system.", args[ 1 ] ); }
GC_CON_COMMAND_PARAMS( gcaccess_catch_job, 2, "<system> <job> - Catches and generates an assert when the specified job calls into the provided system. This will only generate a single assert" ) { if( !GGCAccess().CatchSingleAssert( args[ 1 ], false, args[ 2 ] ) ) EG_MSG( SPEW_CONSOLE, "Unable to register catch, likely \'%s\' is not a valid system.", args[ 1 ] ); }
GC_CON_COMMAND( gcaccess_catch_clear, "Clears all previously specified catches" ) { GGCAccess().ClearSingleAsserts(); }
} //namespace GCSDK
|