From 691f069743bd0cf06cb070ee14c8e4ef51977550 Mon Sep 17 00:00:00 2001
From: JamePeng <jame_peng@sina.com>
Date: Sun, 2 Oct 2016 16:04:50 +0800
Subject: [PATCH] Rework the code of err:f service

---
 src/core/hle/service/err_f.cpp | 312 +++++++++++++++++++++------------
 1 file changed, 196 insertions(+), 116 deletions(-)

diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 3ca4f98de9..9905757c78 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -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
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////