diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index f1d381b80..c4ce86e86 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -113,7 +113,8 @@ void CrashReport::HandleException(DebugEventInfo &d) { default: return; } - /* TODO: Parse crashing thread info. */ + /* Parse crashing thread info. */ + this->crashed_thread_info.ReadFromProcess(this->debug_handle, d.thread_id, Is64Bit()); } bool CrashReport::IsAddressReadable(u64 address, u64 size, MemoryInfo *o_mi) { diff --git a/stratosphere/creport/source/creport_crash_report.hpp b/stratosphere/creport/source/creport_crash_report.hpp index 1cb0c2349..68fbecafd 100644 --- a/stratosphere/creport/source/creport_crash_report.hpp +++ b/stratosphere/creport/source/creport_crash_report.hpp @@ -3,6 +3,7 @@ #include #include "creport_debug_types.hpp" +#include "creport_thread_info.hpp" enum class CrashReportResult : Result { UndefinedInstruction = 0x00A8, @@ -31,6 +32,7 @@ class CrashReport { /* Exception Info. */ ExceptionInfo exception_info; + ThreadInfo crashed_thread_info; public: CrashReport() : debug_handle(INVALID_HANDLE), result((Result)CrashReportResult::IncompleteReport), process_info({}), exception_info({}) { } diff --git a/stratosphere/creport/source/creport_debug_types.hpp b/stratosphere/creport/source/creport_debug_types.hpp index b8ae4e1e4..c17b32772 100644 --- a/stratosphere/creport/source/creport_debug_types.hpp +++ b/stratosphere/creport/source/creport_debug_types.hpp @@ -1,6 +1,11 @@ #pragma once #include +struct StackFrame { + u64 fp; + u64 lr; +}; + struct AttachProcessInfo { u64 title_id; u64 process_id; diff --git a/stratosphere/creport/source/creport_thread_info.cpp b/stratosphere/creport/source/creport_thread_info.cpp new file mode 100644 index 000000000..b429aa0d6 --- /dev/null +++ b/stratosphere/creport/source/creport_thread_info.cpp @@ -0,0 +1,50 @@ +#include + +#include "creport_thread_info.hpp" + +bool ThreadInfo::ReadFromProcess(Handle debug_handle, u64 thread_id, bool is_64_bit) { + this->thread_id = thread_id; + + /* Verify that the thread is running or waiting. */ + { + u64 _; + u32 thread_state; + if (R_FAILED(svcGetDebugThreadParam(&_, &thread_state, debug_handle, this->thread_id, DebugThreadParam_State))) { + return false; + } + + if (thread_state > 1) { + return false; + } + } + + /* Get the thread context. */ + if (R_FAILED(svcGetDebugThreadContext((u8 *)&this->context, debug_handle, this->thread_id, 0xF))) { + return false; + } + + /* Don't try to parse stack frames if 32-bit. */ + if (!is_64_bit) { + return true; + } + + u64 cur_fp = this->context.fp; + for (unsigned int i = 0; i < sizeof(this->stack_trace)/sizeof(u64); i++) { + /* Validate the current frame. */ + if (cur_fp == 0 || (cur_fp & 0xF)) { + break; + } + + /* Read a new frame. */ + StackFrame cur_frame; + if (R_FAILED(svcReadDebugProcessMemory(&cur_frame, debug_handle, cur_fp, sizeof(StackFrame)))) { + break; + } + + /* Advance to the next frame. */ + this->stack_trace[this->stack_trace_size++] = cur_frame.lr; + cur_fp = cur_frame.lr; + } + + return true; +} \ No newline at end of file diff --git a/stratosphere/creport/source/creport_thread_info.hpp b/stratosphere/creport/source/creport_thread_info.hpp new file mode 100644 index 000000000..b36f5cfb2 --- /dev/null +++ b/stratosphere/creport/source/creport_thread_info.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +#include "creport_debug_types.hpp" + +struct FpuReg { + u64 _[2]; /* TODO: uint128? */ +}; + +struct DebugThreadContext { + union { + u64 x[0x20]; + struct { + u64 _x[29]; + u64 fp; + u64 lr; + u64 sp; + }; + }; + u64 pc; + u32 psr; + /* 32-bits of padding. */ + FpuReg fpu_reg[0x20]; + u32 fpcr; + u32 fpsr; + u64 tpidr; +}; + +static_assert(sizeof(DebugThreadContext) == 0x320, "Incorrect DebugThreadContext Definition!"); + +class ThreadInfo { + private: + DebugThreadContext context; + u64 thread_id; + u64 stack_top; + u64 stack_bottom; + u64 stack_trace[0x20]; + u32 stack_trace_size; + public: + ThreadInfo() { + (*this) = {}; + } + + bool ReadFromProcess(Handle debug_handle, u64 thread_id, bool is_64_bit); +}; \ No newline at end of file