From f9799f8ef397a1eb71811087c8faefe4be40a5c2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Nov 2023 11:00:15 +0100 Subject: [PATCH 1/3] Update old code --- .../Platform/Android/AndroidPlatformTools.cpp | 24 ++++++++++++------- .../CodeEditors/VisualStudioCodeEditor.cpp | 5 +++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp index 7d05409e5..995f19fce 100644 --- a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp @@ -280,17 +280,25 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data) const Char* gradlew = TEXT("gradlew"); #endif #if PLATFORM_LINUX - Platform::RunProcess(String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath), data.OriginalOutputPath, Dictionary(), true); + { + CreateProcessSettings procSettings; + procSettings.FileName = String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath); + procSettings.WorkingDirectory = data.OriginalOutputPath; + procSettings.HiddenWindow = true; + Platform::CreateProcess(procSettings); + } #endif const bool distributionPackage = buildSettings->ForDistribution; - CreateProcessSettings procSettings; - procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug")); - procSettings.WorkingDirectory = data.OriginalOutputPath; - const int32 result = Platform::CreateProcess(procSettings); - if (result != 0) { - data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result)); - return true; + CreateProcessSettings procSettings; + procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug")); + procSettings.WorkingDirectory = data.OriginalOutputPath; + const int32 result = Platform::CreateProcess(procSettings); + if (result != 0) + { + data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result)); + return true; + } } // Copy result package diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudioCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/VisualStudioCodeEditor.cpp index adccbba54..93fe7b300 100644 --- a/Source/Editor/Scripting/CodeEditors/VisualStudioCodeEditor.cpp +++ b/Source/Editor/Scripting/CodeEditors/VisualStudioCodeEditor.cpp @@ -78,7 +78,10 @@ void VisualStudioCodeEditor::FindEditors(Array* output) // Detect Flatpak installations { - if (Platform::RunProcess(TEXT("/bin/bash -c \"flatpak list --app --columns=application | grep com.visualstudio.code -c\""), String::Empty) == 0) + CreateProcessSettings procSettings; + procSettings.FileName = TEXT("/bin/bash -c \"flatpak list --app --columns=application | grep com.visualstudio.code -c\""); + procSettings.HiddenWindow = true; + if (Platform::CreateProcess(procSettings) == 0) { const String runPath(TEXT("flatpak run com.visualstudio.code")); output->Add(New(runPath, false)); From 31aafeb0d13f254aa8efeb211c79294986fb49e0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Nov 2023 11:04:10 +0100 Subject: [PATCH 2/3] Add GetStackFrames and IsDebuggerPresent on Linux --- .../Engine/Platform/Linux/LinuxPlatform.cpp | 76 +++++++++++++++++++ Source/Engine/Platform/Linux/LinuxPlatform.h | 4 + 2 files changed, 80 insertions(+) diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index 36affd8c8..a7634710f 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -50,6 +50,10 @@ #include #include #include +#if CRASH_LOG_ENABLE +#include +#include +#endif CPUInfo UnixCpu; int ClockSource; @@ -1868,6 +1872,46 @@ void LinuxPlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int3 millisecond = time.tv_usec / 1000; } +#if !BUILD_RELEASE + +bool LinuxPlatform::IsDebuggerPresent() +{ + static int32 CachedState = -1; + if (CachedState == -1) + { + CachedState = 0; + + // Reference: https://stackoverflow.com/questions/3596781/how-to-detect-if-the-current-process-is-being-run-by-gdb + char buf[4096]; + const int status_fd = open("/proc/self/status", O_RDONLY); + if (status_fd == -1) + return false; + const ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1); + close(status_fd); + if (num_read <= 0) + return false; + buf[num_read] = '\0'; + constexpr char tracerPidString[] = "TracerPid:"; + const auto tracer_pid_ptr = strstr(buf, tracerPidString); + if (!tracer_pid_ptr) + return false; + for (const char* characterPtr = tracer_pid_ptr + sizeof(tracerPidString) - 1; characterPtr <= buf + num_read; ++characterPtr) + { + if (StringUtils::IsWhitespace(*characterPtr)) + continue; + else + { + if (StringUtils::IsDigit(*characterPtr) && *characterPtr != '0') + CachedState = 1; + return CachedState == 1; + } + } + } + return CachedState == 1; +} + +#endif + bool LinuxPlatform::Init() { if (PlatformBase::Init()) @@ -2992,4 +3036,36 @@ void* LinuxPlatform::GetProcAddress(void* handle, const char* symbol) return dlsym(handle, symbol); } +Array LinuxPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) +{ + Array result; +#if CRASH_LOG_ENABLE + void* callstack[120]; + skipCount = Math::Min(skipCount, ARRAY_COUNT(callstack)); + int32 maxCount = Math::Min(ARRAY_COUNT(callstack), skipCount + maxDepth); + int32 count = backtrace(callstack, maxCount); + int32 useCount = count - skipCount; + if (useCount > 0) + { + char** names = backtrace_symbols(callstack + skipCount, useCount); + result.Resize(useCount); + for (int32 i = 0; i < useCount; i++) + { + char* name = names[i]; + StackFrame& frame = result[i]; + frame.ProgramCounter = callstack[skipCount + i]; + frame.ModuleName[0] = 0; + frame.FileName[0] = 0; + frame.LineNumber = 0; + int32 nameLen = Math::Min(StringUtils::Length(name), ARRAY_COUNT(frame.FunctionName) - 1); + Platform::MemoryCopy(frame.FunctionName, name, nameLen); + frame.FunctionName[nameLen] = 0; + + } + free(names); + } +#endif + return result; +} + #endif diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.h b/Source/Engine/Platform/Linux/LinuxPlatform.h index 827a6b635..54590adf2 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.h +++ b/Source/Engine/Platform/Linux/LinuxPlatform.h @@ -114,6 +114,9 @@ public: } static void GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond); static void GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond); +#if !BUILD_RELEASE + static bool IsDebuggerPresent(); +#endif static bool Init(); static void BeforeRun(); static void Tick(); @@ -143,6 +146,7 @@ public: static void* LoadLibrary(const Char* filename); static void FreeLibrary(void* handle); static void* GetProcAddress(void* handle, const char* symbol); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); }; #endif From 389bf89e2a105e808178590c0212afe361ee3667 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 19 Nov 2023 11:07:40 +0100 Subject: [PATCH 3/3] Add `GetStackFrames` on Android --- .../Platform/Android/AndroidPlatform.cpp | 68 +++++++++++++++++++ .../Engine/Platform/Android/AndroidPlatform.h | 1 + 2 files changed, 69 insertions(+) diff --git a/Source/Engine/Platform/Android/AndroidPlatform.cpp b/Source/Engine/Platform/Android/AndroidPlatform.cpp index c844ab81d..e71d4534a 100644 --- a/Source/Engine/Platform/Android/AndroidPlatform.cpp +++ b/Source/Engine/Platform/Android/AndroidPlatform.cpp @@ -51,6 +51,33 @@ #include #include +#if CRASH_LOG_ENABLE + +#include +#include + +struct AndroidBacktraceState +{ + void** Current; + void** End; +}; + +_Unwind_Reason_Code AndroidUnwindCallback(struct _Unwind_Context* context, void* arg) +{ + AndroidBacktraceState* state = (AndroidBacktraceState*)arg; + uintptr_t pc = _Unwind_GetIP(context); + if (pc) + { + if (state->Current == state->End) + return _URC_END_OF_STACK; + else + *state->Current++ = reinterpret_cast(pc); + } + return _URC_NO_REASON; +} + +#endif + struct AndroidKeyEventType { uint32_t KeyCode; @@ -1066,4 +1093,45 @@ void* AndroidPlatform::GetProcAddress(void* handle, const char* symbol) return dlsym(handle, symbol); } +Array AndroidPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context) +{ + Array result; +#if CRASH_LOG_ENABLE + // Reference: https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace + void* callstack[120]; + skipCount = Math::Min(skipCount, ARRAY_COUNT(callstack)); + int32 maxCount = Math::Min(ARRAY_COUNT(callstack), skipCount + maxDepth); + AndroidBacktraceState state; + state.Current = callstack; + state.End = callstack + maxCount; + _Unwind_Backtrace(AndroidUnwindCallback, &state); + int32 count = (int32)(state.Current - callstack); + int32 useCount = count - skipCount; + if (useCount > 0) + { + result.Resize(useCount); + for (int32 i = 0; i < useCount; i++) + { + StackFrame& frame = result[i]; + frame.ProgramCounter = callstack[skipCount + i]; + frame.ModuleName[0] = 0; + frame.FileName[0] = 0; + frame.LineNumber = 0; + Dl_info info; + const char* symbol = ""; + if (dladdr(frame.ProgramCounter, &info) && info.dli_sname) + symbol = info.dli_sname; + int status = 0; + char* demangled = __cxxabiv1::__cxa_demangle(symbol, 0, 0, &status); + int32 nameLen = Math::Min(StringUtils::Length(demangled), ARRAY_COUNT(frame.FunctionName) - 1); + Platform::MemoryCopy(frame.FunctionName, demangled, nameLen); + frame.FunctionName[nameLen] = 0; + if (demangled) + free(demangled); + } + } +#endif + return result; +} + #endif diff --git a/Source/Engine/Platform/Android/AndroidPlatform.h b/Source/Engine/Platform/Android/AndroidPlatform.h index 07e72cac4..577da45de 100644 --- a/Source/Engine/Platform/Android/AndroidPlatform.h +++ b/Source/Engine/Platform/Android/AndroidPlatform.h @@ -132,6 +132,7 @@ public: static void* LoadLibrary(const Char* filename); static void FreeLibrary(void* handle); static void* GetProcAddress(void* handle, const char* symbol); + static Array GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr); }; #endif