citra/src/core/hle/service/err_f.cpp

254 lines
8.6 KiB
C++
Raw Normal View History

2014-11-02 04:06:13 +01:00
// Copyright 2014 Citra Emulator Project
2014-12-17 06:38:14 +01:00
// Licensed under GPLv2 or any later version
2014-11-02 04:06:13 +01:00
// Refer to the license.txt file included.
2016-10-02 10:04:50 +02:00
#include <array>
#include <chrono>
#include <iomanip>
#include <sstream>
#include "common/bit_field.h"
#include "common/common_types.h"
2015-05-06 09:06:12 +02:00
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
2016-10-02 10:04:50 +02:00
#include "core/hle/result.h"
#include "core/hle/service/err_f.h"
2015-05-06 09:06:12 +02:00
namespace Service {
namespace ERR {
2014-11-02 04:06:13 +01:00
2016-10-02 10:04:50 +02:00
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;
};
2016-10-02 10:04:50 +02:00
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");
2016-10-02 10:04:50 +02:00
struct ErrInfo {
struct ErrInfoCommon {
u8 specifier; // 0x0
u8 rev_high; // 0x1
u16 rev_low; // 0x2
u32 result_code; // 0x4
2016-10-02 10:04:50 +02:00
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;
};
};
2016-10-02 10:04:50 +02:00
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";
}
}
2016-10-02 10:04:50 +02:00
static std::string GetExceptionType(u8 type_code) {
switch (static_cast<ExceptionType>(type_code)) {
case ExceptionType::PrefetchAbort:
return "Prefetch Abort";
2016-10-02 10:04:50 +02:00
case ExceptionType::DataAbort:
return "Data Abort";
2016-10-02 10:04:50 +02:00
case ExceptionType::Undefined:
return "Undefined Exception";
case ExceptionType::VectorFP:
return "Vector Floating Point Exception";
default:
2016-10-02 10:04:50 +02:00
return "Unknown Exception Type";
}
}
2016-10-02 10:04:50 +02:00
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) {
2018-06-29 13:18:07 +02:00
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);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "TID: 0x{:08X}_0x{:08X}", errinfo_common.title_id_high,
errinfo_common.title_id_low);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "AID: 0x{:08X}_0x{:08X}", errinfo_common.app_title_id_high,
errinfo_common.app_title_id_low);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "ADR: 0x{:08X}", errinfo_common.pc_address);
2016-10-02 10:04:50 +02:00
ResultCode result_code{errinfo_common.result_code};
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "RSL: 0x{:08X}", result_code.raw);
LOG_CRITICAL(Service_ERR, " Level: {}", static_cast<u32>(result_code.level.Value()));
LOG_CRITICAL(Service_ERR, " Summary: {}", static_cast<u32>(result_code.summary.Value()));
LOG_CRITICAL(Service_ERR, " Module: {}", static_cast<u32>(result_code.module.Value()));
LOG_CRITICAL(Service_ERR, " Desc: {}", static_cast<u32>(result_code.description.Value()));
2016-10-02 10:04:50 +02:00
}
void ERR_F::ThrowFatalError(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 1, 32, 0);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "Fatal error");
const ErrInfo errinfo = rp.PopRaw<ErrInfo>();
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "Fatal error type: {}",
GetErrType(errinfo.errinfo_common.specifier));
Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown);
2016-10-02 10:04:50 +02:00
// Generic Info
LogGenericInfo(errinfo.errinfo_common);
2016-10-02 10:04:50 +02:00
switch (static_cast<FatalErrType>(errinfo.errinfo_common.specifier)) {
2016-10-02 10:04:50 +02:00
case FatalErrType::Generic:
case FatalErrType::Corrupted:
case FatalErrType::CardRemoved:
case FatalErrType::Logged: {
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
break;
}
2016-10-02 10:04:50 +02:00
case FatalErrType::Exception: {
const auto& errtype = errinfo.exception;
2016-10-02 10:04:50 +02:00
// Register Info
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "ARM Registers:");
2016-10-02 10:04:50 +02:00
for (u32 index = 0; index < errtype.exception_data.exception_context.arm_regs.size();
++index) {
if (index < 13) {
2018-06-29 13:18:07 +02:00
LOG_DEBUG(Service_ERR, "r{}=0x{:08X}", index,
errtype.exception_data.exception_context.arm_regs.at(index));
2016-10-02 10:04:50 +02:00
} else if (index == 13) {
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "SP=0x{:08X}",
errtype.exception_data.exception_context.arm_regs.at(index));
2016-10-02 10:04:50 +02:00
} else if (index == 14) {
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "LR=0x{:08X}",
errtype.exception_data.exception_context.arm_regs.at(index));
2016-10-02 10:04:50 +02:00
} else if (index == 15) {
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "PC=0x{:08X}",
errtype.exception_data.exception_context.arm_regs.at(index));
2016-10-02 10:04:50 +02:00
}
}
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "CPSR=0x{:08X}", errtype.exception_data.exception_context.cpsr);
2016-10-02 10:04:50 +02:00
// Exception Info
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "EXCEPTION TYPE: {}",
GetExceptionType(errtype.exception_data.exception_info.exception_type));
2016-10-02 10:04:50 +02:00
switch (static_cast<ExceptionType>(errtype.exception_data.exception_info.exception_type)) {
case ExceptionType::PrefetchAbort:
2018-06-29 13:18:07 +02:00
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);
break;
2016-10-02 10:04:50 +02:00
case ExceptionType::DataAbort:
2018-06-29 13:18:07 +02:00
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;
2016-10-02 10:04:50 +02:00
case ExceptionType::VectorFP:
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "FPEXC: 0x{:08X}",
errtype.exception_data.exception_info.fpinst);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "FINST: 0x{:08X}",
errtype.exception_data.exception_info.fpinst);
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "FINST2: 0x{:08X}",
errtype.exception_data.exception_info.fpinst2);
break;
case ExceptionType::Undefined:
break; // Not logging exception_info for this case
}
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
break;
}
2016-10-02 10:04:50 +02:00
case FatalErrType::ResultFailure: {
const auto& errtype = errinfo.result_failure;
2016-10-02 10:04:50 +02:00
// Failure Message
2018-06-29 13:18:07 +02:00
LOG_CRITICAL(Service_ERR, "Failure Message: {}", errtype.message);
LOG_CRITICAL(Service_ERR, "Datetime: {}", GetCurrentSystemTime());
break;
}
2016-10-02 10:04:50 +02:00
} // switch FatalErrType
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
ERR_F::ERR_F() : ServiceFramework("err:f", 1) {
static const FunctionInfo functions[] = {
{0x00010800, &ERR_F::ThrowFatalError, "ThrowFatalError"},
{0x00020042, nullptr, "SetUserString"},
};
RegisterHandlers(functions);
}
ERR_F::~ERR_F() = default;
2014-11-02 04:06:13 +01:00
void InstallInterfaces() {
auto errf = std::make_shared<ERR_F>();
errf->InstallAsNamedPort();
2014-12-21 20:52:10 +01:00
}
} // namespace ERR
} // namespace Service