|
|
@ -2,9 +2,15 @@ |
|
|
// Licensed under GPLv2 or any later version
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
// Refer to the license.txt file included.
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
|
#include <chrono>
|
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
#include "common/bit_field.h"
|
|
|
#include "common/bit_field.h"
|
|
|
#include "common/common_types.h"
|
|
|
#include "common/common_types.h"
|
|
|
#include "common/logging/log.h"
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
|
#include "core/hle/result.h"
|
|
|
#include "core/hle/service/err_f.h"
|
|
|
#include "core/hle/service/err_f.h"
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
@ -12,12 +18,45 @@ |
|
|
|
|
|
|
|
|
namespace ERR_F { |
|
|
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
|
|
|
// This is used instead of ResultCode from result.h
|
|
|
// because we can't have non-trivial data members in unions.
|
|
|
// because we can't have non-trivial data members in unions.
|
|
|
@ -30,150 +69,191 @@ union RSL { |
|
|
BitField<27, 5, u32> level; |
|
|
BitField<27, 5, u32> level; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
union ErrInfo { |
|
|
|
|
|
u8 specifier; |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
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 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"); |
|
|
|
|
|
|
|
|
|
|
|
union { |
|
|
|
|
|
struct { |
|
|
|
|
|
char data[0x60]; // 0x20
|
|
|
|
|
|
} generic; |
|
|
|
|
|
|
|
|
|
|
|
struct { |
|
|
|
|
|
ExceptionData exception_data; // 0x20
|
|
|
|
|
|
} exception; |
|
|
|
|
|
|
|
|
|
|
|
struct { |
|
|
|
|
|
char message[0x60]; // 0x20
|
|
|
|
|
|
} result_failure; |
|
|
|
|
|
}; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 }; |
|
|
|
|
|
|
|
|
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 Error Type"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static std::string GetErrInfo3Type(u8 type_code) { |
|
|
|
|
|
switch (type_code) { |
|
|
|
|
|
case PrefetchAbort: |
|
|
|
|
|
|
|
|
static std::string GetExceptionType(u8 type_code) { |
|
|
|
|
|
switch (static_cast<ExceptionType>(type_code)) { |
|
|
|
|
|
case ExceptionType::PrefetchAbort: |
|
|
return "Prefetch Abort"; |
|
|
return "Prefetch Abort"; |
|
|
case DataAbort: |
|
|
|
|
|
|
|
|
case ExceptionType::DataAbort: |
|
|
return "Data Abort"; |
|
|
return "Data Abort"; |
|
|
case UndefInstr: |
|
|
|
|
|
return "Undefined Instruction"; |
|
|
|
|
|
case VectorFP: |
|
|
|
|
|
return "Vector Floating Point"; |
|
|
|
|
|
|
|
|
case ExceptionType::Undefined: |
|
|
|
|
|
return "Undefined Exception"; |
|
|
|
|
|
case ExceptionType::VectorFP: |
|
|
|
|
|
return "Vector Floating Point Exception"; |
|
|
default: |
|
|
default: |
|
|
return "unknown"; |
|
|
|
|
|
|
|
|
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) { |
|
|
static void ThrowFatalError(Service::Interface* self) { |
|
|
u32* cmd_buff = Kernel::GetCommandBuffer(); |
|
|
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]); |
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
|
|
|
|
// Generic Info
|
|
|
|
|
|
LogGenericInfo(errinfo->errinfo_common); |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
case FatalErrType::Exception: { |
|
|
|
|
|
const auto& errtype = errinfo->exception; |
|
|
|
|
|
|
|
|
|
|
|
// 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); |
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
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; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
LOG_CRITICAL(Service_ERR, "Datetime: %s", GetCurrentSystemTime().c_str()); |
|
|
break; |
|
|
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; |
|
|
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[] = { |
|
|
const Interface::FunctionInfo FunctionTable[] = { |
|
|
|
|
|
// clang-format off
|
|
|
{0x00010800, ThrowFatalError, "ThrowFatalError"}, |
|
|
{0x00010800, ThrowFatalError, "ThrowFatalError"}, |
|
|
|
|
|
{0x00020042, nullptr, "SetUserString"}, |
|
|
|
|
|
// clang-format on
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|