Added debugger attachment utilities to the engine, fixed crash when showing console variables, improvements to timeout handling and small cleanup (#3591)
* Added debugger attachment utilities to the engine, fixed crash when showing console variables Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Removed unused variables Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Removed unneded check Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Small fix for crashes/timeouts Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Removed unused variable, fixed compile error Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Fix compile Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk> * Addressed esteban comments * Addressed tom comments Co-authored-by: Garcia Ruiz <aljanru@amazon.co.uk>
This commit is contained in:
@@ -573,6 +573,10 @@ static CVarBlock* VarBlockFromConsoleVars()
|
||||
IVariable* pVariable = nullptr;
|
||||
for (int i = 0; i < cmdCount; i++)
|
||||
{
|
||||
if (!cmds[i].data())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ICVar* pCVar = console->GetCVar(cmds[i].data());
|
||||
if (!pCVar)
|
||||
{
|
||||
|
||||
+17
-2
@@ -551,7 +551,9 @@ public:
|
||||
{ "NSDocumentRevisionsDebugMode", nsDocumentRevisionsDebugMode},
|
||||
{ "skipWelcomeScreenDialog", m_bSkipWelcomeScreenDialog},
|
||||
{ "autotest_mode", m_bAutotestMode},
|
||||
{ "regdumpall", dummy }
|
||||
{ "regdumpall", dummy },
|
||||
{ "attach-debugger", dummy }, // Attaches a debugger for the current application
|
||||
{ "wait-for-debugger", dummy }, // Waits until a debugger is attached to the current application
|
||||
};
|
||||
|
||||
QString dummyString;
|
||||
@@ -2290,7 +2292,7 @@ int CCryEditApp::IdleProcessing(bool bBackgroundUpdate)
|
||||
int res = 0;
|
||||
if (bIsAppWindow || m_bForceProcessIdle || m_bKeepEditorActive
|
||||
// Automated tests must always keep the editor active, or they can get stuck
|
||||
|| m_bAutotestMode)
|
||||
|| m_bAutotestMode || m_bRunPythonTestScript)
|
||||
{
|
||||
res = 1;
|
||||
bActive = true;
|
||||
@@ -4011,6 +4013,19 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
{
|
||||
CryAllocatorsRAII cryAllocatorsRAII;
|
||||
|
||||
// Debugging utilities
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (azstricmp(argv[i], "--attach-debugger") == 0)
|
||||
{
|
||||
AZ::Debug::Trace::AttachDebugger();
|
||||
}
|
||||
else if (azstricmp(argv[i], "--wait-for-debugger") == 0)
|
||||
{
|
||||
AZ::Debug::Trace::WaitForDebugger();
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the EditorEventsBus context gets created inside EditorLib
|
||||
[[maybe_unused]] const auto& editorEventsContext = AzToolsFramework::EditorEvents::Bus::GetOrCreateContext();
|
||||
|
||||
|
||||
@@ -401,6 +401,16 @@ inline namespace Commands
|
||||
{
|
||||
return static_cast<int>(GetIEditor()->GetEditorConfigPlatform());
|
||||
}
|
||||
|
||||
bool PyAttachDebugger()
|
||||
{
|
||||
return AZ::Debug::Trace::AttachDebugger();
|
||||
}
|
||||
|
||||
bool PyWaitForDebugger(float timeoutSeconds = -1.f)
|
||||
{
|
||||
return AZ::Debug::Trace::WaitForDebugger(timeoutSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -448,6 +458,9 @@ namespace AzToolsFramework
|
||||
addLegacyGeneral(behaviorContext->Method("start_process_detached", PyStartProcessDetached, nullptr, "Launches a detached process with an optional space separated list of arguments."));
|
||||
addLegacyGeneral(behaviorContext->Method("launch_lua_editor", PyLaunchLUAEditor, nullptr, "Launches the Lua editor, may receive a list of space separate file paths, or an empty string to only open the editor."));
|
||||
|
||||
addLegacyGeneral(behaviorContext->Method("attach_debugger", PyAttachDebugger, nullptr, "Prompts for attaching the debugger"));
|
||||
addLegacyGeneral(behaviorContext->Method("wait_for_debugger", PyWaitForDebugger, behaviorContext->MakeDefaultValues(-1.f), "Pauses this thread execution until the debugger has been attached"));
|
||||
|
||||
// this will put these methods into the 'azlmbr.legacy.checkout_dialog' module
|
||||
auto addCheckoutDialog = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -33,6 +34,7 @@ namespace AZ
|
||||
namespace Platform
|
||||
{
|
||||
#if defined(AZ_ENABLE_DEBUG_TOOLS)
|
||||
bool AttachDebugger();
|
||||
bool IsDebuggerPresent();
|
||||
void HandleExceptions(bool isEnabled);
|
||||
void DebugBreak();
|
||||
@@ -141,6 +143,40 @@ namespace AZ
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Trace::AttachDebugger()
|
||||
{
|
||||
#if defined(AZ_ENABLE_DEBUG_TOOLS)
|
||||
return Platform::AttachDebugger();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Trace::WaitForDebugger(float timeoutSeconds/*=-1.f*/)
|
||||
{
|
||||
#if defined(AZ_ENABLE_DEBUG_TOOLS)
|
||||
using AZStd::chrono::system_clock;
|
||||
using AZStd::chrono::time_point;
|
||||
using AZStd::chrono::milliseconds;
|
||||
|
||||
milliseconds timeoutMs = milliseconds(aznumeric_cast<long long>(timeoutSeconds * 1000));
|
||||
system_clock clock;
|
||||
time_point start = clock.now();
|
||||
auto hasTimedOut = [&clock, start, timeoutMs]()
|
||||
{
|
||||
return timeoutMs.count() >= 0 && (clock.now() - start) >= timeoutMs;
|
||||
};
|
||||
|
||||
while (!AZ::Debug::Trace::IsDebuggerPresent() && !hasTimedOut())
|
||||
{
|
||||
AZStd::this_thread::sleep_for(milliseconds(1));
|
||||
}
|
||||
return AZ::Debug::Trace::IsDebuggerPresent();
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// HandleExceptions
|
||||
// [8/3/2009]
|
||||
|
||||
@@ -49,6 +49,8 @@ namespace AZ
|
||||
*/
|
||||
static const char* GetDefaultSystemWindow();
|
||||
static bool IsDebuggerPresent();
|
||||
static bool AttachDebugger();
|
||||
static bool WaitForDebugger(float timeoutSeconds = -1.f);
|
||||
|
||||
/// True or false if we want to handle system exceptions.
|
||||
static void HandleExceptions(bool isEnabled);
|
||||
|
||||
@@ -56,6 +56,13 @@ namespace AZ
|
||||
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||
}
|
||||
|
||||
bool AttachDebugger()
|
||||
{
|
||||
// Not supported yet
|
||||
AZ_Assert(false, "AttachDebugger() is not supported for Mac platform yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleExceptions(bool)
|
||||
{}
|
||||
|
||||
|
||||
@@ -60,6 +60,13 @@ namespace AZ
|
||||
return s_debuggerDetected;
|
||||
}
|
||||
|
||||
bool AttachDebugger()
|
||||
{
|
||||
// Not supported yet
|
||||
AZ_Assert(false, "AttachDebugger() is not supported for Unix platform yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleExceptions(bool)
|
||||
{}
|
||||
|
||||
|
||||
@@ -49,6 +49,45 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
bool AttachDebugger()
|
||||
{
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Launch vsjitdebugger.exe, this app is always present in System32 folder
|
||||
// with an installation of any version of visual studio.
|
||||
// It will open a debugging dialog asking the user what debugger to use
|
||||
|
||||
STARTUPINFOW startupInfo = {0};
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
PROCESS_INFORMATION processInfo = {0};
|
||||
|
||||
wchar_t cmdline[MAX_PATH];
|
||||
swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
|
||||
bool success = ::CreateProcessW(
|
||||
NULL, // No module name (use command line)
|
||||
cmdline, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // No handle inheritance
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&startupInfo, // Pointer to STARTUPINFO structure
|
||||
&processInfo); // Pointer to PROCESS_INFORMATION structure
|
||||
|
||||
if (success)
|
||||
{
|
||||
::WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||
::CloseHandle(processInfo.hProcess);
|
||||
::CloseHandle(processInfo.hThread);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DebugBreak()
|
||||
{
|
||||
__debugbreak();
|
||||
|
||||
Reference in New Issue
Block a user