mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #1654 from JamePeng/errdisp
Rework the code of err:f service!
This commit is contained in:
		
						commit
						fefa645ec7
					
				
					 1 changed files with 196 additions and 116 deletions
				
			
		|  | @ -2,9 +2,15 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include <chrono> | ||||
| #include <iomanip> | ||||
| #include <sstream> | ||||
| 
 | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/err_f.h" | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|  | @ -12,13 +18,46 @@ | |||
| 
 | ||||
| namespace ERR_F { | ||||
| 
 | ||||
| enum { | ||||
|     ErrSpecifier0 = 0, | ||||
|     ErrSpecifier1 = 1, | ||||
|     ErrSpecifier3 = 3, | ||||
|     ErrSpecifier4 = 4, | ||||
| enum class FatalErrType : u32 { | ||||
|     Generic = 0, | ||||
|     Corrupted = 1, | ||||
|     CardRemoved = 2, | ||||
|     Exception = 3, | ||||
|     ResultFailure = 4, | ||||
|     Logged = 5, | ||||
| }; | ||||
| 
 | ||||
| enum class ExceptionType : u32 { | ||||
|     PrefetchAbort = 0, | ||||
|     DataAbort = 1, | ||||
|     Undefined = 2, | ||||
|     VectorFP = 3, | ||||
| }; | ||||
| 
 | ||||
| struct ExceptionInfo { | ||||
|     u8 exception_type; | ||||
|     INSERT_PADDING_BYTES(3); | ||||
|     u32 sr; | ||||
|     u32 ar; | ||||
|     u32 fpexc; | ||||
|     u32 fpinst; | ||||
|     u32 fpinst2; | ||||
| }; | ||||
| static_assert(sizeof(ExceptionInfo) == 0x18, "ExceptionInfo struct has incorrect size"); | ||||
| 
 | ||||
| struct ExceptionContext final { | ||||
|     std::array<u32, 16> arm_regs; | ||||
|     u32 cpsr; | ||||
| }; | ||||
| static_assert(sizeof(ExceptionContext) == 0x44, "ExceptionContext struct has incorrect size"); | ||||
| 
 | ||||
| struct ExceptionData { | ||||
|     ExceptionInfo exception_info; | ||||
|     ExceptionContext exception_context; | ||||
|     INSERT_PADDING_WORDS(1); | ||||
| }; | ||||
| static_assert(sizeof(ExceptionData) == 0x60, "ExceptionData struct has incorrect size"); | ||||
| 
 | ||||
| // This is used instead of ResultCode from result.h
 | ||||
| // because we can't have non-trivial data members in unions.
 | ||||
| union RSL { | ||||
|  | @ -30,150 +69,191 @@ union RSL { | |||
|     BitField<27, 5, u32> level; | ||||
| }; | ||||
| 
 | ||||
| union ErrInfo { | ||||
|     u8 specifier; | ||||
| struct ErrInfo { | ||||
|     struct ErrInfoCommon { | ||||
|         u8 specifier;          // 0x0
 | ||||
|         u8 rev_high;           // 0x1
 | ||||
|         u16 rev_low;           // 0x2
 | ||||
|         RSL result_code;       // 0x4
 | ||||
|         u32 pc_address;        // 0x8
 | ||||
|         u32 pid;               // 0xC
 | ||||
|         u32 title_id_low;      // 0x10
 | ||||
|         u32 title_id_high;     // 0x14
 | ||||
|         u32 app_title_id_low;  // 0x18
 | ||||
|         u32 app_title_id_high; // 0x1C
 | ||||
|     } errinfo_common; | ||||
|     static_assert(sizeof(ErrInfoCommon) == 0x20, "ErrInfoCommon struct has incorrect size"); | ||||
| 
 | ||||
|     struct { | ||||
|         u8 specifier;            // 0x0
 | ||||
|         u8 rev_high;             // 0x1
 | ||||
|         u16 rev_low;             // 0x2
 | ||||
|         RSL result_code;         // 0x4
 | ||||
|         u32 address;             // 0x8
 | ||||
|         INSERT_PADDING_BYTES(4); // 0xC
 | ||||
|         u32 pid_low;             // 0x10
 | ||||
|         u32 pid_high;            // 0x14
 | ||||
|         u32 aid_low;             // 0x18
 | ||||
|         u32 aid_high;            // 0x1C
 | ||||
|     } errtype1; | ||||
|     union { | ||||
|         struct { | ||||
|             char data[0x60]; // 0x20
 | ||||
|         } generic; | ||||
| 
 | ||||
|     struct { | ||||
|         u8 specifier;               // 0x0
 | ||||
|         u8 rev_high;                // 0x1
 | ||||
|         u16 rev_low;                // 0x2
 | ||||
|         INSERT_PADDING_BYTES(0xC);  // 0x4
 | ||||
|         u32 pid_low;                // 0x10
 | ||||
|         u32 pid_high;               // 0x14
 | ||||
|         u32 aid_low;                // 0x18
 | ||||
|         u32 aid_high;               // 0x1C
 | ||||
|         u8 error_type;              // 0x20
 | ||||
|         INSERT_PADDING_BYTES(3);    // 0x21
 | ||||
|         u32 fault_status_reg;       // 0x24
 | ||||
|         u32 fault_addr;             // 0x28
 | ||||
|         u32 fpexc;                  // 0x2C
 | ||||
|         u32 finst;                  // 0x30
 | ||||
|         u32 finst2;                 // 0x34
 | ||||
|         INSERT_PADDING_BYTES(0x34); // 0x38
 | ||||
|         u32 sp;                     // 0x6C
 | ||||
|         u32 pc;                     // 0x70
 | ||||
|         u32 lr;                     // 0x74
 | ||||
|         u32 cpsr;                   // 0x78
 | ||||
|     } errtype3; | ||||
|         struct { | ||||
|             ExceptionData exception_data; // 0x20
 | ||||
|         } exception; | ||||
| 
 | ||||
|     struct { | ||||
|         u8 specifier;             // 0x0
 | ||||
|         u8 rev_high;              // 0x1
 | ||||
|         u16 rev_low;              // 0x2
 | ||||
|         RSL result_code;          // 0x4
 | ||||
|         INSERT_PADDING_BYTES(8);  // 0x8
 | ||||
|         u32 pid_low;              // 0x10
 | ||||
|         u32 pid_high;             // 0x14
 | ||||
|         u32 aid_low;              // 0x18
 | ||||
|         u32 aid_high;             // 0x1C
 | ||||
|         char debug_string1[0x2E]; // 0x20
 | ||||
|         char debug_string2[0x2E]; // 0x4E
 | ||||
|     } errtype4; | ||||
|         struct { | ||||
|             char message[0x60]; // 0x20
 | ||||
|         } result_failure; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 }; | ||||
| 
 | ||||
| static std::string GetErrInfo3Type(u8 type_code) { | ||||
|     switch (type_code) { | ||||
|     case PrefetchAbort: | ||||
|         return "Prefetch Abort"; | ||||
|     case DataAbort: | ||||
|         return "Data Abort"; | ||||
|     case UndefInstr: | ||||
|         return "Undefined Instruction"; | ||||
|     case VectorFP: | ||||
|         return "Vector Floating Point"; | ||||
| static std::string GetErrType(u8 type_code) { | ||||
|     switch (static_cast<FatalErrType>(type_code)) { | ||||
|     case FatalErrType::Generic: | ||||
|         return "Generic"; | ||||
|     case FatalErrType::Corrupted: | ||||
|         return "Corrupted"; | ||||
|     case FatalErrType::CardRemoved: | ||||
|         return "CardRemoved"; | ||||
|     case FatalErrType::Exception: | ||||
|         return "Exception"; | ||||
|     case FatalErrType::ResultFailure: | ||||
|         return "ResultFailure"; | ||||
|     case FatalErrType::Logged: | ||||
|         return "Logged"; | ||||
|     default: | ||||
|         return "unknown"; | ||||
|         return "Unknown Error Type"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static std::string GetExceptionType(u8 type_code) { | ||||
|     switch (static_cast<ExceptionType>(type_code)) { | ||||
|     case ExceptionType::PrefetchAbort: | ||||
|         return "Prefetch Abort"; | ||||
|     case ExceptionType::DataAbort: | ||||
|         return "Data Abort"; | ||||
|     case ExceptionType::Undefined: | ||||
|         return "Undefined Exception"; | ||||
|     case ExceptionType::VectorFP: | ||||
|         return "Vector Floating Point Exception"; | ||||
|     default: | ||||
|         return "Unknown Exception Type"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static std::string GetCurrentSystemTime() { | ||||
|     auto now = std::chrono::system_clock::now(); | ||||
|     auto time = std::chrono::system_clock::to_time_t(now); | ||||
| 
 | ||||
|     std::stringstream time_stream; | ||||
|     time_stream << std::put_time(std::localtime(&time), "%Y/%m/%d %H:%M:%S"); | ||||
|     return time_stream.str(); | ||||
| } | ||||
| 
 | ||||
| static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) { | ||||
|     LOG_CRITICAL(Service_ERR, "PID: 0x%08X", errinfo_common.pid); | ||||
|     LOG_CRITICAL(Service_ERR, "REV: 0x%08X_0x%08X", errinfo_common.rev_high, | ||||
|                  errinfo_common.rev_low); | ||||
|     LOG_CRITICAL(Service_ERR, "TID: 0x%08X_0x%08X", errinfo_common.title_id_high, | ||||
|                  errinfo_common.title_id_low); | ||||
|     LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errinfo_common.app_title_id_high, | ||||
|                  errinfo_common.app_title_id_low); | ||||
|     LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errinfo_common.pc_address); | ||||
| 
 | ||||
|     LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errinfo_common.result_code.raw); | ||||
|     LOG_CRITICAL(Service_ERR, "  Level: %u", errinfo_common.result_code.level.Value()); | ||||
|     LOG_CRITICAL(Service_ERR, "  Summary: %u", errinfo_common.result_code.summary.Value()); | ||||
|     LOG_CRITICAL(Service_ERR, "  Module: %u", errinfo_common.result_code.module.Value()); | ||||
|     LOG_CRITICAL(Service_ERR, "  Desc: %u", errinfo_common.result_code.description.Value()); | ||||
| } | ||||
| 
 | ||||
| /* ThrowFatalError function
 | ||||
|  * Inputs: | ||||
|  *       0 : Header code [0x00010800] | ||||
|  *    1-32 : FatalErrInfo | ||||
|  * Outputs: | ||||
|  *       0 : Header code | ||||
|  *       1 : Result code | ||||
|  */ | ||||
| static void ThrowFatalError(Service::Interface* self) { | ||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     LOG_CRITICAL(Service_ERR, "Fatal error!"); | ||||
|     LOG_CRITICAL(Service_ERR, "Fatal error"); | ||||
|     const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); | ||||
|     LOG_CRITICAL(Service_ERR, "Fatal error type: %s", | ||||
|                  GetErrType(errinfo->errinfo_common.specifier).c_str()); | ||||
| 
 | ||||
|     switch (errinfo->specifier) { | ||||
|     case ErrSpecifier0: | ||||
|     case ErrSpecifier1: { | ||||
|         const auto& errtype = errinfo->errtype1; | ||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | ||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | ||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | ||||
|         LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errtype.address); | ||||
|     // Generic Info
 | ||||
|     LogGenericInfo(errinfo->errinfo_common); | ||||
| 
 | ||||
|         LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); | ||||
|         LOG_CRITICAL(Service_ERR, "  Level: %u", errtype.result_code.level.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Summary: %u", errtype.result_code.summary.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Module: %u", errtype.result_code.module.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Desc: %u", errtype.result_code.description.Value()); | ||||
|     switch (static_cast<FatalErrType>(errinfo->errinfo_common.specifier)) { | ||||
|     case FatalErrType::Generic: | ||||
|     case FatalErrType::Corrupted: | ||||
|     case FatalErrType::CardRemoved: | ||||
|     case FatalErrType::Logged: { | ||||
|         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||
|         break; | ||||
|     } | ||||
|     case FatalErrType::Exception: { | ||||
|         const auto& errtype = errinfo->exception; | ||||
| 
 | ||||
|     case ErrSpecifier3: { | ||||
|         const auto& errtype = errinfo->errtype3; | ||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | ||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | ||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | ||||
|         LOG_CRITICAL(Service_ERR, "TYPE: %s", GetErrInfo3Type(errtype.error_type).c_str()); | ||||
|         // Register Info
 | ||||
|         LOG_CRITICAL(Service_ERR, "ARM Registers:"); | ||||
|         for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size(); | ||||
|              ++index) { | ||||
|             if (index < 13) { | ||||
|                 LOG_DEBUG(Service_ERR, "r%u=0x%08X", index, | ||||
|                           errtype.exception_data.exception_context.arm_regs.at(index)); | ||||
|             } else if (index == 13) { | ||||
|                 LOG_CRITICAL(Service_ERR, "SP=0x%08X", | ||||
|                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||
|             } else if (index == 14) { | ||||
|                 LOG_CRITICAL(Service_ERR, "LR=0x%08X", | ||||
|                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||
|             } else if (index == 15) { | ||||
|                 LOG_CRITICAL(Service_ERR, "PC=0x%08X", | ||||
|                              errtype.exception_data.exception_context.arm_regs.at(index)); | ||||
|             } | ||||
|         } | ||||
|         LOG_CRITICAL(Service_ERR, "CPSR=0x%08X", errtype.exception_data.exception_context.cpsr); | ||||
| 
 | ||||
|         LOG_CRITICAL(Service_ERR, "PC: 0x%08X", errtype.pc); | ||||
|         LOG_CRITICAL(Service_ERR, "LR: 0x%08X", errtype.lr); | ||||
|         LOG_CRITICAL(Service_ERR, "SP: 0x%08X", errtype.sp); | ||||
|         LOG_CRITICAL(Service_ERR, "CPSR: 0x%08X", errtype.cpsr); | ||||
| 
 | ||||
|         switch (errtype.error_type) { | ||||
|         case PrefetchAbort: | ||||
|         case DataAbort: | ||||
|             LOG_CRITICAL(Service_ERR, "Fault Address: 0x%08X", errtype.fault_addr); | ||||
|             LOG_CRITICAL(Service_ERR, "Fault Status Register: 0x%08X", errtype.fault_status_reg); | ||||
|         // Exception Info
 | ||||
|         LOG_CRITICAL( | ||||
|             Service_ERR, "EXCEPTION TYPE: %s", | ||||
|             GetExceptionType(errtype.exception_data.exception_info.exception_type).c_str()); | ||||
|         switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) { | ||||
|         case ExceptionType::PrefetchAbort: | ||||
|             LOG_CRITICAL(Service_ERR, "IFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||||
|             LOG_CRITICAL(Service_ERR, "r15: 0x%08X", errtype.exception_data.exception_info.ar); | ||||
|         case ExceptionType::DataAbort: | ||||
|             LOG_CRITICAL(Service_ERR, "DFSR: 0x%08X", errtype.exception_data.exception_info.sr); | ||||
|             LOG_CRITICAL(Service_ERR, "DFAR: 0x%08X", errtype.exception_data.exception_info.ar); | ||||
|             break; | ||||
|         case VectorFP: | ||||
|             LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", errtype.fpexc); | ||||
|             LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", errtype.finst); | ||||
|             LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", errtype.finst2); | ||||
|         case ExceptionType::VectorFP: | ||||
|             LOG_CRITICAL(Service_ERR, "FPEXC: 0x%08X", | ||||
|                          errtype.exception_data.exception_info.fpinst); | ||||
|             LOG_CRITICAL(Service_ERR, "FINST: 0x%08X", | ||||
|                          errtype.exception_data.exception_info.fpinst); | ||||
|             LOG_CRITICAL(Service_ERR, "FINST2: 0x%08X", | ||||
|                          errtype.exception_data.exception_info.fpinst2); | ||||
|             break; | ||||
|         } | ||||
|         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case ErrSpecifier4: { | ||||
|         const auto& errtype = errinfo->errtype4; | ||||
|         LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high); | ||||
|         LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16)); | ||||
|         LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high); | ||||
|     case FatalErrType::ResultFailure: { | ||||
|         const auto& errtype = errinfo->result_failure; | ||||
| 
 | ||||
|         LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw); | ||||
|         LOG_CRITICAL(Service_ERR, "  Level: %u", errtype.result_code.level.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Summary: %u", errtype.result_code.summary.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Module: %u", errtype.result_code.module.Value()); | ||||
|         LOG_CRITICAL(Service_ERR, "  Desc: %u", errtype.result_code.description.Value()); | ||||
| 
 | ||||
|         LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1); | ||||
|         LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2); | ||||
|         // Failure Message
 | ||||
|         LOG_CRITICAL(Service_ERR, "Failure Message: %s", errtype.message); | ||||
|         LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     cmd_buff[1] = 0; // No error
 | ||||
|     } // switch FatalErrType
 | ||||
| 
 | ||||
|     cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||
| } | ||||
| 
 | ||||
| const Interface::FunctionInfo FunctionTable[] = { | ||||
|     // clang-format off
 | ||||
|     {0x00010800, ThrowFatalError, "ThrowFatalError"}, | ||||
|     {0x00020042, nullptr, "SetUserString"}, | ||||
|     // clang-format on
 | ||||
| }; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue