b3b646dad9
* Moved the loading of the AssetCatalog from LmbrCentralSystemComponent to AzFramework Application Modified the AssetCatalog::InitializeCatalog function to no longer rely on the TickBus to send out the `AssetCatalogEventBus::OnCatalogLoaded` event. It now queues a function on the AssetCatalogRequestBus to send the OnCatalogLoaded event as soon as the dispatching for the AssetCatalogRequestBus has completed on the current thread. This is done by updating the AssetCatalogRequestBus to use EBus ThreadDispatchPolicy to add a callback to invoke any queued function has soon a thread has finished dispatching and has released its DispatchMutex Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetCatalogRequestBus to add a custom DispatchLockGuard The AssetCatalogRequestBus uses the custom lock guard to dispatch queued events after it has unlocked it's context mutex for the current thread. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed GetContext call from the AssetCatalogRequests::PostThreadDispatchInvoker Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the definition of FileTagQueryManager::GetDefaultFileTagFilePath function to return a path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AZ_CONSOLEFREEFUNC macro to actually use the _NAME The _NAME parameter was not being used before, resulting in the Console stringified name of the function being used. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed CrySystem dependencies from the BundlingSystemComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the loading of the AssetCatalog from LmbrCentralSystemComponent to AzFramework Application Modified the AssetCatalog::InitializeCatalog function to no longer rely on the TickBus to send out the `AssetCatalogEventBus::OnCatalogLoaded` event. It now queues a function on the AssetCatalogRequestBus to send the OnCatalogLoaded event as soon as the dispatching for the AssetCatalogRequestBus has completed on the current thread. This is done by updating the AssetCatalogRequestBus to use EBus ThreadDispatchPolicy to add a callback to invoke any queued function has soon a thread has finished dispatching and has released its DispatchMutex Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetCatalogRequestBus to add a custom DispatchLockGuard The AssetCatalogRequestBus uses the custom lock guard to dispatch queued events after it has unlocked it's context mutex for the current thread. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed GetContext call from the AssetCatalogRequests::PostThreadDispatchInvoker Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the definition of FileTagQueryManager::GetDefaultFileTagFilePath function to return a path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AZ_CONSOLEFREEFUNC macro to actually use the _NAME The _NAME parameter was not being used before, resulting in the Console stringified name of the function being used. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed CrySystem dependencies from the BundlingSystemComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Addded missing template parameter to AssetCatalogRequests The fixes the compile error. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding AssetBus::MultiHandler::BusDisconnect call The BlastSystemComponent was connecting to the Bus, but not disconnecting from it, causing an assert to fire to it being a multi-thread bus Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added support for DataDrive lifecycle events to the ComponentApplication The events are using the SettingsRegistry NotifyEvent to track when certain keys are modified to signal handlers. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Corrected invalid JSON creation in ModuleManager::DeactivateEntities Resolved clang warning about used type alias Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix for dangling reference in lambda registered to the SettingsRegistry Notifier event This was causing the EditorPythonBinding tests to crash due to the following circumstances. First Python has created an instance of a SettingsRegistryProxy Second the SettingsRegistry sends an event during the time when the SettingsRegistryProxy exists. This issue was exposed due to the ComponentApplication Lifecycle events using the SettingsRegistry to dispatch during various times of the application workflow. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
272 lines
8.1 KiB
C++
272 lines
8.1 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
// Description : A multiplatform base class for handling errors and collecting call stacks
|
|
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
#include "IDebugCallStack.h"
|
|
#include "System.h"
|
|
#include <AzFramework/IO/FileOperations.h>
|
|
#include <AzCore/NativeUI/NativeUIRequests.h>
|
|
#include <AzCore/StringFunc/StringFunc.h>
|
|
#include <AzCore/Utils/Utils.h>
|
|
//#if !defined(LINUX)
|
|
|
|
#include <ISystem.h>
|
|
|
|
const char* const IDebugCallStack::s_szFatalErrorCode = "FATAL_ERROR";
|
|
|
|
IDebugCallStack::IDebugCallStack()
|
|
: m_bIsFatalError(false)
|
|
, m_postBackupProcess(0)
|
|
, m_memAllocFileHandle(AZ::IO::InvalidHandle)
|
|
{
|
|
}
|
|
|
|
IDebugCallStack::~IDebugCallStack()
|
|
{
|
|
StopMemLog();
|
|
}
|
|
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_SINGLETON
|
|
IDebugCallStack* IDebugCallStack::instance()
|
|
{
|
|
static IDebugCallStack sInstance;
|
|
return &sInstance;
|
|
}
|
|
#endif
|
|
|
|
void IDebugCallStack::FileCreationCallback(void (* postBackupProcess)())
|
|
{
|
|
m_postBackupProcess = postBackupProcess;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void IDebugCallStack::LogCallstack()
|
|
{
|
|
AZ::Debug::Trace::PrintCallstack("", 2);
|
|
}
|
|
|
|
const char* IDebugCallStack::TranslateExceptionCode(DWORD dwExcept)
|
|
{
|
|
switch (dwExcept)
|
|
{
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_TRANSLATE
|
|
case EXCEPTION_ACCESS_VIOLATION:
|
|
return "EXCEPTION_ACCESS_VIOLATION";
|
|
break;
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
|
return "EXCEPTION_DATATYPE_MISALIGNMENT";
|
|
break;
|
|
case EXCEPTION_BREAKPOINT:
|
|
return "EXCEPTION_BREAKPOINT";
|
|
break;
|
|
case EXCEPTION_SINGLE_STEP:
|
|
return "EXCEPTION_SINGLE_STEP";
|
|
break;
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
|
return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
|
break;
|
|
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
|
return "EXCEPTION_FLT_DENORMAL_OPERAND";
|
|
break;
|
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
|
return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
|
break;
|
|
case EXCEPTION_FLT_INEXACT_RESULT:
|
|
return "EXCEPTION_FLT_INEXACT_RESULT";
|
|
break;
|
|
case EXCEPTION_FLT_INVALID_OPERATION:
|
|
return "EXCEPTION_FLT_INVALID_OPERATION";
|
|
break;
|
|
case EXCEPTION_FLT_OVERFLOW:
|
|
return "EXCEPTION_FLT_OVERFLOW";
|
|
break;
|
|
case EXCEPTION_FLT_STACK_CHECK:
|
|
return "EXCEPTION_FLT_STACK_CHECK";
|
|
break;
|
|
case EXCEPTION_FLT_UNDERFLOW:
|
|
return "EXCEPTION_FLT_UNDERFLOW";
|
|
break;
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
|
return "EXCEPTION_INT_DIVIDE_BY_ZERO";
|
|
break;
|
|
case EXCEPTION_INT_OVERFLOW:
|
|
return "EXCEPTION_INT_OVERFLOW";
|
|
break;
|
|
case EXCEPTION_PRIV_INSTRUCTION:
|
|
return "EXCEPTION_PRIV_INSTRUCTION";
|
|
break;
|
|
case EXCEPTION_IN_PAGE_ERROR:
|
|
return "EXCEPTION_IN_PAGE_ERROR";
|
|
break;
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
|
return "EXCEPTION_ILLEGAL_INSTRUCTION";
|
|
break;
|
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
|
return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
|
break;
|
|
case EXCEPTION_STACK_OVERFLOW:
|
|
return "EXCEPTION_STACK_OVERFLOW";
|
|
break;
|
|
case EXCEPTION_INVALID_DISPOSITION:
|
|
return "EXCEPTION_INVALID_DISPOSITION";
|
|
break;
|
|
case EXCEPTION_GUARD_PAGE:
|
|
return "EXCEPTION_GUARD_PAGE";
|
|
break;
|
|
case EXCEPTION_INVALID_HANDLE:
|
|
return "EXCEPTION_INVALID_HANDLE";
|
|
break;
|
|
//case EXCEPTION_POSSIBLE_DEADLOCK: return "EXCEPTION_POSSIBLE_DEADLOCK"; break ;
|
|
|
|
case STATUS_FLOAT_MULTIPLE_FAULTS:
|
|
return "STATUS_FLOAT_MULTIPLE_FAULTS";
|
|
break;
|
|
case STATUS_FLOAT_MULTIPLE_TRAPS:
|
|
return "STATUS_FLOAT_MULTIPLE_TRAPS";
|
|
break;
|
|
|
|
|
|
#endif
|
|
default:
|
|
return "Unknown";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void IDebugCallStack::PutVersion(char* str, size_t length)
|
|
{
|
|
AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
|
|
|
|
if (!gEnv || !gEnv->pSystem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char sFileVersion[128];
|
|
gEnv->pSystem->GetFileVersion().ToString(sFileVersion, sizeof(sFileVersion));
|
|
|
|
char sProductVersion[128];
|
|
gEnv->pSystem->GetProductVersion().ToString(sProductVersion, sizeof(sFileVersion));
|
|
|
|
|
|
//! Get time.
|
|
time_t ltime;
|
|
time(<ime);
|
|
tm* today = localtime(<ime);
|
|
|
|
char s[1024];
|
|
//! Use strftime to build a customized time string.
|
|
strftime(s, 128, "Logged at %#c\n", today);
|
|
azstrcat(str, length, s);
|
|
sprintf_s(s, "FileVersion: %s\n", sFileVersion);
|
|
azstrcat(str, length, s);
|
|
sprintf_s(s, "ProductVersion: %s\n", sProductVersion);
|
|
azstrcat(str, length, s);
|
|
|
|
if (gEnv->pLog)
|
|
{
|
|
const char* logfile = gEnv->pLog->GetFileName();
|
|
if (logfile)
|
|
{
|
|
sprintf (s, "LogFile: %s\n", logfile);
|
|
azstrcat(str, length, s);
|
|
}
|
|
}
|
|
|
|
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
|
|
azstrcat(str, length, "ProjectDir: ");
|
|
azstrcat(str, length, projectPath.c_str());
|
|
azstrcat(str, length, "\n");
|
|
|
|
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_APPEND_MODULENAME
|
|
AZ::Utils::GetExecutablePath(s, sizeof(s));
|
|
|
|
// Log EXE filename only if possible (not full EXE path which could contain sensitive info)
|
|
AZStd::string exeName;
|
|
if (AZ::StringFunc::Path::GetFullFileName(s, exeName))
|
|
{
|
|
azstrcat(str, length, "Executable: ");
|
|
azstrcat(str, length, exeName.c_str());
|
|
|
|
# ifdef AZ_DEBUG_BUILD
|
|
azstrcat(str, length, " (debug: yes");
|
|
# else
|
|
azstrcat(str, length, " (debug: no");
|
|
# endif
|
|
}
|
|
#endif
|
|
AZ_POP_DISABLE_WARNING
|
|
}
|
|
|
|
|
|
//Crash the application, in this way the debug callstack routine will be called and it will create all the necessary files (error.log, dump, and eventually screenshot)
|
|
void IDebugCallStack::FatalError(const char* description)
|
|
{
|
|
m_bIsFatalError = true;
|
|
WriteLineToLog(description);
|
|
|
|
#ifndef _RELEASE
|
|
bool bShowDebugScreen = g_cvars.sys_no_crash_dialog == 0;
|
|
// showing the debug screen is not safe when not called from mainthread
|
|
// it normally leads to a infinity recursion followed by a stack overflow, preventing
|
|
// useful call stacks, thus they are disabled
|
|
bShowDebugScreen = bShowDebugScreen && gEnv->mMainThreadId == CryGetCurrentThreadId();
|
|
if (bShowDebugScreen)
|
|
{
|
|
EBUS_EVENT(AZ::NativeUI::NativeUIRequestBus, DisplayOkDialog, "Open 3D Engine Fatal Error", description, false);
|
|
}
|
|
#endif
|
|
|
|
#if defined(WIN32) || !defined(_RELEASE)
|
|
int* p = 0x0;
|
|
*p = 1; // we're intentionally crashing here
|
|
#endif
|
|
}
|
|
|
|
void IDebugCallStack::WriteLineToLog(const char* format, ...)
|
|
{
|
|
va_list ArgList;
|
|
char szBuffer[MAX_WARNING_LENGTH];
|
|
va_start(ArgList, format);
|
|
vsnprintf_s(szBuffer, sizeof(szBuffer), sizeof(szBuffer) - 1, format, ArgList);
|
|
azstrcat(szBuffer, MAX_WARNING_LENGTH, "\n");
|
|
szBuffer[sizeof(szBuffer) - 1] = '\0';
|
|
va_end(ArgList);
|
|
|
|
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle);
|
|
if (fileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Write(fileHandle, szBuffer, strlen(szBuffer));
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Flush(fileHandle);
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Close(fileHandle);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void IDebugCallStack::StartMemLog()
|
|
{
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle);
|
|
|
|
assert(m_memAllocFileHandle != AZ::IO::InvalidHandle);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void IDebugCallStack::StopMemLog()
|
|
{
|
|
if (m_memAllocFileHandle != AZ::IO::InvalidHandle)
|
|
{
|
|
AZ::IO::FileIOBase::GetDirectInstance()->Close(m_memAllocFileHandle);
|
|
m_memAllocFileHandle = AZ::IO::InvalidHandle;
|
|
}
|
|
}
|
|
//#endif //!defined(LINUX)
|