diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 70c243fafce4..c634635f3a9c 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -76,6 +76,46 @@ void fmt_class_string::format(std::string& out, u64 arg) } } +#ifndef _WIN32 +bool IsDebuggerPresent() +{ + char buf[4096]; + fs::file status_fd("/proc/self/status"); + if (!status_fd) + { + std::fprintf(stderr, "Failed to open /proc/self/status\n"); + return false; + } + + const auto num_read = status_fd.read(buf, sizeof(buf) - 1); + if (num_read == 0 || num_read == umax) + { + std::fprintf(stderr, "Failed to read /proc/self/status (%d)\n", errno); + return false; + } + + buf[num_read] = '\0'; + std::string_view status = buf; + + const auto found = status.find("TracerPid:"); + if (found == umax) + { + std::fprintf(stderr, "Failed to find 'TracerPid:' in /proc/self/status\n"); + return false; + } + + for (const char* cp = status.data() + found + 10; cp <= status.data() + num_read; ++cp) + { + if (!std::isspace(*cp)) + { + return std::isdigit(*cp) != 0 && *cp != '0'; + } + } + + return false; +} +#endif + enum x64_reg_t : u32 { X64R_RAX = 0, @@ -1449,7 +1489,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no if (!access_violation_recovered) { vm_log.notice("\n%s", cpu->dump()); - vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory"); + vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory"); } // TODO: @@ -1723,10 +1763,11 @@ const bool s_exception_handler_set = []() -> bool if (::sigaction(SIGSEGV, &sa, NULL) == -1) { - std::printf("sigaction(SIGSEGV) failed (0x%x).", errno); + std::fprintf(stderr, "sigaction(SIGSEGV) failed (0x%x).", errno); std::abort(); } + std::printf("Debugger: %d\n", +IsDebuggerPresent()); return true; }(); @@ -2022,6 +2063,21 @@ void thread_ctrl::emergency_exit(std::string_view reason) { sig_log.fatal("Thread terminated due to fatal error: %s", reason); + std::fprintf(stderr, "Thread '%s' terminated due to fatal error: %s\n", g_tls_log_prefix().c_str(), std::string(reason).c_str()); + +#ifdef _WIN32 + if (IsDebuggerPresent()) + { + OutputDebugStringA(fmt::format("Thread '%s' terminated due to fatal error: %s\n", g_tls_log_prefix(), reason).c_str()); + __debugbreak(); + } +#else + if (IsDebuggerPresent()) + { + __asm("int3;"); + } +#endif + if (const auto _this = g_tls_this_thread) { if (_this->finalize(0)) diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index fd57c2450cf8..1adb381725d3 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -152,7 +152,7 @@ struct pause_on_fatal final : logs::listener void log(u64 /*stamp*/, const logs::message& msg, const std::string& /*prefix*/, const std::string& /*text*/) override { - if (msg.sev <= logs::level::fatal) + if (msg.sev == logs::level::fatal) { // Pause emulation if fatal error encountered Emu.Pause(); diff --git a/rpcs3/util/logs.hpp b/rpcs3/util/logs.hpp index 45c41ea6ea54..51dd1a571a34 100644 --- a/rpcs3/util/logs.hpp +++ b/rpcs3/util/logs.hpp @@ -14,7 +14,7 @@ namespace logs enum class level : unsigned { - always, // Highest log severity (unused, cannot be disabled) + always, // Highest log severity (cannot be disabled) fatal, error, todo, @@ -103,6 +103,7 @@ namespace logs }\ }\ + GEN_LOG_METHOD(always) GEN_LOG_METHOD(fatal) GEN_LOG_METHOD(error) GEN_LOG_METHOD(todo)