From d3eb267ba9c35823a0ebcd63008e69a4c5fda970 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2020 11:23:56 +0300 Subject: [PATCH 1/3] Logs: add 'always' method for debugging --- rpcs3/util/logs.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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) From 87d4b14ca960a23464db55fc5f2ab1fb703b42ff Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2020 11:24:32 +0300 Subject: [PATCH 2/3] Pause only on fatal messages Also make some access violation an error since we don't pause on it. --- Utilities/Thread.cpp | 2 +- rpcs3/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 70c243fafce4..ad480f9c03de 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1449,7 +1449,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: 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(); From adfd8ab43c5b80c6a654e11719abd677b4d283f8 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2020 11:31:11 +0300 Subject: [PATCH 3/3] Break in the debugger in thread_ctrl::emergency_exit Implement IsDebuggerPresent analog for non-Windows systems. --- Utilities/Thread.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index ad480f9c03de..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, @@ -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))