diff --git a/stratosphere/creport/source/creport_crash_report.cpp b/stratosphere/creport/source/creport_crash_report.cpp index 70a686c67..f1d381b80 100644 --- a/stratosphere/creport/source/creport_crash_report.cpp +++ b/stratosphere/creport/source/creport_crash_report.cpp @@ -43,23 +43,11 @@ void CrashReport::HandleAttachProcess(DebugEventInfo &d) { this->process_info = d.info.attach_process; if (kernelAbove500() && IsApplication()) { /* Parse out user data. */ - MemoryInfo mi; - u32 pi; u64 address = this->process_info.user_exception_context_address; u64 userdata_address = 0; u64 userdata_size = 0; - if (R_FAILED(svcQueryDebugProcessMemory(&mi, &pi, this->debug_handle, address))) { - return; - } - - /* Must be read or read-write */ - if ((mi.perm | Perm_W) != Perm_Rw) { - return; - } - - /* Must have space for both userdata address and userdata size. */ - if (address < mi.addr || mi.addr + mi.size < address + 2 * sizeof(u64)) { + if (!IsAddressReadable(address, sizeof(userdata_address) + sizeof(userdata_size))) { return; } @@ -90,20 +78,65 @@ void CrashReport::HandleAttachProcess(DebugEventInfo &d) { } void CrashReport::HandleException(DebugEventInfo &d) { + this->exception_info = d.info.exception; switch (d.info.exception.type) { case DebugExceptionType::UndefinedInstruction: + this->result = (Result)CrashReportResult::UndefinedInstruction; + break; case DebugExceptionType::InstructionAbort: + this->result = (Result)CrashReportResult::InstructionAbort; + this->exception_info.specific.raw = 0; + break; case DebugExceptionType::DataAbort: + this->result = (Result)CrashReportResult::DataAbort; + break; case DebugExceptionType::AlignmentFault: + this->result = (Result)CrashReportResult::AlignmentFault; + break; case DebugExceptionType::UserBreak: + this->result = (Result)CrashReportResult::UserBreak; + /* Try to parse out the user break result. */ + if (kernelAbove500() && IsAddressReadable(this->exception_info.specific.user_break.address, sizeof(this->result))) { + svcReadDebugProcessMemory(&this->result, this->debug_handle, this->exception_info.specific.user_break.address, sizeof(this->result)); + } + break; case DebugExceptionType::BadSvc: + this->result = (Result)CrashReportResult::BadSvc; + break; case DebugExceptionType::UnknownNine: - /* TODO: Handle these exceptions...creport seems to discard all but the latest exception? */ + this->result = (Result)CrashReportResult::UnknownNine; + this->exception_info.specific.raw = 0; break; case DebugExceptionType::DebuggerAttached: case DebugExceptionType::BreakPoint: case DebugExceptionType::DebuggerBreak: default: - break; + return; } + /* TODO: Parse crashing thread info. */ +} + +bool CrashReport::IsAddressReadable(u64 address, u64 size, MemoryInfo *o_mi) { + MemoryInfo mi; + u32 pi; + + if (o_mi == NULL) { + o_mi = &mi; + } + + if (R_FAILED(svcQueryDebugProcessMemory(o_mi, &pi, this->debug_handle, address))) { + return false; + } + + /* Must be read or read-write */ + if ((o_mi->perm | Perm_W) != Perm_Rw) { + return false; + } + + /* Must have space for both userdata address and userdata size. */ + if (address < o_mi->addr || o_mi->addr + o_mi->size < address + size) { + return false; + } + + return true; } \ No newline at end of file diff --git a/stratosphere/creport/source/creport_crash_report.hpp b/stratosphere/creport/source/creport_crash_report.hpp index 2d9e8586f..1cb0c2349 100644 --- a/stratosphere/creport/source/creport_crash_report.hpp +++ b/stratosphere/creport/source/creport_crash_report.hpp @@ -29,13 +29,18 @@ class CrashReport { u64 userdata_5x_address; u64 userdata_5x_size; + /* Exception Info. */ + ExceptionInfo exception_info; + public: - CrashReport() : debug_handle(INVALID_HANDLE), result((Result)CrashReportResult::IncompleteReport), process_info({0}) { } + CrashReport() : debug_handle(INVALID_HANDLE), result((Result)CrashReportResult::IncompleteReport), process_info({}), exception_info({}) { } void BuildReport(u64 pid, bool has_extra_info); void SaveReport(); void ProcessExceptions(); + bool IsAddressReadable(u64 address, u64 size, MemoryInfo *mi = NULL); + Result GetResult() { return this->result; } @@ -68,7 +73,7 @@ class CrashReport { } bool IsUserBreak() { - return this->result == (Result)CrashReportResult::UserBreak; + return this->exception_info.type == DebugExceptionType::UserBreak; } private: void HandleAttachProcess(DebugEventInfo &d); diff --git a/stratosphere/creport/source/creport_debug_types.hpp b/stratosphere/creport/source/creport_debug_types.hpp index b0e752ff7..b8ae4e1e4 100644 --- a/stratosphere/creport/source/creport_debug_types.hpp +++ b/stratosphere/creport/source/creport_debug_types.hpp @@ -43,6 +43,12 @@ struct AlignmentFaultInfo { u64 address; }; +struct UserBreakInfo { + u64 info_0; + u64 address; + u64 size; +}; + struct BadSvcInfo { u32 id; }; @@ -51,12 +57,11 @@ union SpecificExceptionInfo { UndefinedInstructionInfo undefined_instruction; DataAbortInfo data_abort; AlignmentFaultInfo alignment_fault; + UserBreakInfo user_break; BadSvcInfo bad_svc; u64 raw; }; -static_assert(sizeof(SpecificExceptionInfo) == sizeof(u64), "Bad SpecificExceptionInfo definition!"); - struct ExceptionInfo { DebugExceptionType type; u64 address;