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.
690 lines
22 KiB
690 lines
22 KiB
//========= 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
|
|
|