mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
fatal: Draw GPRs + Backtrace to screen.
This commit is contained in:
parent
f16423c413
commit
20026587fd
6 changed files with 253 additions and 14 deletions
|
@ -48,6 +48,28 @@ IEvent *GetFatalSettingsEvent() {
|
|||
return g_fatal_settings_event;
|
||||
}
|
||||
|
||||
static void SetupConfigLanguages() {
|
||||
FatalConfig *config = GetFatalConfig();
|
||||
|
||||
/* Defaults. */
|
||||
config->error_msg = u8"Error Code: 2%03d-%04d (0x%x)\n";
|
||||
|
||||
if (config->quest_flag) {
|
||||
config->error_desc = u8"Please call 1-800-875-1852 for service.\n";
|
||||
} else {
|
||||
config->error_desc = u8"An error has occured.\n\n"
|
||||
u8"Please press the POWER Button to restart the console. If you are\n"
|
||||
u8"unable to restart the console, hold the POWER Button for 12 seconds\n"
|
||||
u8"to turn the console off.\n\n"
|
||||
u8"If the problem persists, refer to the Nintendo Support Website.\n"
|
||||
u8"nintendo.com/switch/error\n";
|
||||
}
|
||||
|
||||
/* TODO: Try to load dynamically. */
|
||||
/* FsStorage message_storage; */
|
||||
/* TODO: if (R_SUCCEEDED(fsOpenDataStorageByDataId(0x010000000000081D, "fatal_msg"))) { ... } */
|
||||
}
|
||||
|
||||
void InitializeFatalConfig() {
|
||||
FatalConfig *config = GetFatalConfig();
|
||||
|
||||
|
@ -61,4 +83,6 @@ void InitializeFatalConfig() {
|
|||
setsysGetSettingsItemValue("fatal", "quest_reboot_interval_second", &config->quest_reboot_interval_second, sizeof(config->quest_reboot_interval_second));
|
||||
|
||||
setsysGetFlag(SetSysFlag_Quest, &config->quest_flag);
|
||||
|
||||
SetupConfigLanguages();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ struct FatalConfig {
|
|||
bool transition_to_fatal;
|
||||
bool show_extra_info;
|
||||
bool quest_flag;
|
||||
const char *error_msg;
|
||||
const char *error_desc;
|
||||
const char *quest_desc;
|
||||
};
|
||||
|
||||
IEvent *GetFatalSettingsEvent();
|
||||
|
|
|
@ -32,7 +32,7 @@ static u16 *g_fb = nullptr;
|
|||
static u32 (*g_unswizzle_func)(u32, u32) = nullptr;
|
||||
static u16 g_font_color = 0xFFFF;
|
||||
static float g_font_sz = 16.0f;
|
||||
static u32 g_cur_x = 0, g_cur_y = 0;
|
||||
static u32 g_line_x = 0, g_cur_x = 0, g_cur_y = 0;
|
||||
|
||||
static PlFontData g_font;
|
||||
static PlFontData g_fonts[PlSharedFontType_Total];
|
||||
|
@ -70,7 +70,7 @@ static void DrawGlyph(FT_Bitmap *bitmap, u32 x, u32 y) {
|
|||
}
|
||||
}
|
||||
|
||||
void FontManager::PrintLine(const char *str) {
|
||||
static void DrawString(const char *str, bool add_line) {
|
||||
FT_UInt glyph_index;
|
||||
FT_GlyphSlot slot = g_face->glyph;
|
||||
|
||||
|
@ -78,9 +78,14 @@ void FontManager::PrintLine(const char *str) {
|
|||
|
||||
u32 cur_x = g_cur_x, cur_y = g_cur_y;
|
||||
ON_SCOPE_EXIT {
|
||||
/* Advance to next line. */
|
||||
/* g_cur_x = g_cur_x; */
|
||||
g_cur_y = cur_y + (g_face->size->metrics.height >> 6);
|
||||
if (add_line) {
|
||||
/* Advance to next line. */
|
||||
g_cur_x = g_line_x;
|
||||
g_cur_y = cur_y + (g_face->size->metrics.height >> 6);
|
||||
} else {
|
||||
g_cur_x = cur_x;
|
||||
g_cur_y = cur_y;
|
||||
}
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < len; ) {
|
||||
|
@ -90,7 +95,7 @@ void FontManager::PrintLine(const char *str) {
|
|||
i += unit_count;
|
||||
|
||||
if (cur_char == '\n') {
|
||||
cur_x = g_cur_x;
|
||||
cur_x = g_line_x;
|
||||
cur_y += g_face->size->metrics.height >> 6;
|
||||
continue;
|
||||
}
|
||||
|
@ -114,6 +119,10 @@ void FontManager::PrintLine(const char *str) {
|
|||
}
|
||||
}
|
||||
|
||||
void FontManager::PrintLine(const char *str) {
|
||||
return DrawString(str, true);
|
||||
}
|
||||
|
||||
void FontManager::PrintFormatLine(const char *format, ...) {
|
||||
va_list va_arg;
|
||||
va_start(va_arg, format);
|
||||
|
@ -124,21 +133,46 @@ void FontManager::PrintFormatLine(const char *format, ...) {
|
|||
PrintLine(char_buf);
|
||||
}
|
||||
|
||||
void FontManager::Print(const char *str) {
|
||||
return DrawString(str, false);
|
||||
}
|
||||
|
||||
void FontManager::PrintFormat(const char *format, ...) {
|
||||
va_list va_arg;
|
||||
va_start(va_arg, format);
|
||||
|
||||
char char_buf[0x400];
|
||||
vsnprintf(char_buf, sizeof(char_buf), format, va_arg);
|
||||
|
||||
Print(char_buf);
|
||||
}
|
||||
|
||||
|
||||
void FontManager::SetFontColor(u16 color) {
|
||||
g_font_color = color;
|
||||
}
|
||||
|
||||
void FontManager::SetPosition(u32 x, u32 y) {
|
||||
g_line_x = x;
|
||||
g_cur_x = x;
|
||||
g_cur_y = y;
|
||||
}
|
||||
|
||||
u32 FontManager::GetX() {
|
||||
return g_cur_x;
|
||||
}
|
||||
|
||||
u32 FontManager::GetY() {
|
||||
return g_cur_y;
|
||||
}
|
||||
|
||||
void FontManager::SetFontSize(float fsz) {
|
||||
g_font_sz = fsz;
|
||||
g_ft_err = FT_Set_Char_Size(g_face, 0, static_cast<u32>(g_font_sz * 64.0f), 96, 96);
|
||||
}
|
||||
|
||||
void FontManager::AddSpacingLines(float num_lines) {
|
||||
g_cur_x = g_line_x;
|
||||
g_cur_y += static_cast<u32>((static_cast<float>(g_face->size->metrics.height) * num_lines) / 64.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,12 @@ class FontManager {
|
|||
|
||||
static void SetFontColor(u16 color);
|
||||
static void SetPosition(u32 x, u32 y);
|
||||
static u32 GetX();
|
||||
static u32 GetY();
|
||||
static void SetFontSize(float fsz);
|
||||
static void AddSpacingLines(float num_lines);
|
||||
static void PrintLine(const char *str);
|
||||
static void PrintFormatLine(const char *format, ...);
|
||||
static void Print(const char *str);
|
||||
static void PrintFormat(const char *format, ...);
|
||||
};
|
|
@ -172,6 +172,7 @@ Result ShowFatalTask::PrepareScreenForDrawing() {
|
|||
|
||||
Result ShowFatalTask::ShowFatal() {
|
||||
Result rc = 0;
|
||||
const FatalConfig *config = GetFatalConfig();
|
||||
|
||||
if (R_FAILED((rc = PrepareScreenForDrawing()))) {
|
||||
*(volatile u32 *)(0xCAFEBABE) = rc;
|
||||
|
@ -196,17 +197,132 @@ Result ShowFatalTask::ShowFatal() {
|
|||
/* Draw the atmosphere logo in the bottom right corner. */
|
||||
for (size_t y = 0; y < AMS_LOGO_HEIGHT; y++) {
|
||||
for (size_t x = 0; x < AMS_LOGO_WIDTH; x++) {
|
||||
tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, FatalScreenHeight - AMS_LOGO_HEIGHT - 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x];
|
||||
tiled_buf[GetPixelOffset(FatalScreenWidth - AMS_LOGO_WIDTH - 32 + x, 32 + y)] = AMS_LOGO_BIN[y * AMS_LOGO_WIDTH + x];
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Actually draw meaningful shit here. */
|
||||
FontManager::SetPosition(32, 64);
|
||||
FontManager::PrintFormatLine(u8"A fatal error occurred: 2%03d-%04d", R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code));
|
||||
FontManager::SetFontSize(16.0f);
|
||||
FontManager::PrintFormatLine("Title: %016lx", this->title_id);
|
||||
FontManager::AddSpacingLines(0.5f);
|
||||
FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version,
|
||||
CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision());
|
||||
FontManager::PrintFormatLine(config->error_msg, R_MODULE(this->ctx->error_code), R_DESCRIPTION(this->ctx->error_code), this->ctx->error_code);
|
||||
FontManager::PrintLine(config->error_desc);
|
||||
FontManager::AddSpacingLines(0.5f);
|
||||
FontManager::PrintFormatLine(u8"Firmware: %s (Atmosphère %u.%u.%u-%s)", GetFatalConfig()->firmware_version.display_version, CURRENT_ATMOSPHERE_VERSION, GetAtmosphereGitRevision());
|
||||
|
||||
/* Add a line. */
|
||||
for (size_t x = 32; x < FatalScreenWidth - 32; x++) {
|
||||
tiled_buf[GetPixelOffset(x, FontManager::GetY())] = 0xFFFF;
|
||||
}
|
||||
|
||||
|
||||
FontManager::AddSpacingLines(1.5f);
|
||||
|
||||
u32 backtrace_y = FontManager::GetY();
|
||||
u32 backtrace_x = 0;
|
||||
|
||||
/* Print GPRs. */
|
||||
FontManager::SetFontSize(14.0f);
|
||||
FontManager::PrintLine("General Purpose Registers");
|
||||
FontManager::AddSpacingLines(0.5f);
|
||||
if (this->ctx->cpu_ctx.is_aarch32) {
|
||||
for (size_t i = 0; i < (NumAarch32Gprs / 2); i++) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("%s:", Aarch32GprNames[i]);
|
||||
FontManager::SetPosition(x + 47, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]);
|
||||
x = FontManager::GetX();
|
||||
FontManager::PrintFormat("%s:", Aarch32GprNames[i + (NumAarch32Gprs / 2)]);
|
||||
FontManager::SetPosition(x + 47, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%08x ", this->ctx->cpu_ctx.aarch32_ctx.r[i]);
|
||||
|
||||
|
||||
FontManager::PrintLine("");
|
||||
FontManager::SetPosition(32, FontManager::GetY());
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < NumAarch64Gprs / 2; i++) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("%s:", Aarch64GprNames[i]);
|
||||
FontManager::SetPosition(x + 47, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]);
|
||||
x = FontManager::GetX();
|
||||
FontManager::PrintFormat("%s:", Aarch64GprNames[i + (NumAarch64Gprs / 2)]);
|
||||
FontManager::SetPosition(x + 47, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%016lx ", this->ctx->cpu_ctx.aarch64_ctx.x[i]);
|
||||
|
||||
if (i == (NumAarch64Gprs / 2) - 1) {
|
||||
FontManager::Print(" ");
|
||||
backtrace_x = FontManager::GetX();
|
||||
}
|
||||
|
||||
FontManager::PrintLine("");
|
||||
FontManager::SetPosition(32, FontManager::GetY());
|
||||
}
|
||||
}
|
||||
|
||||
/* Print Backtrace. */
|
||||
FontManager::SetPosition(backtrace_x, backtrace_y);
|
||||
if (this->ctx->cpu_ctx.is_aarch32) {
|
||||
FontManager::PrintFormatLine("Backtrace (Start Address = 0x%08x)", this->ctx->cpu_ctx.aarch32_ctx.start_address);
|
||||
FontManager::AddSpacingLines(0.5f);
|
||||
for (u32 i = 0; i < Aarch32CpuContext::MaxStackTraceDepth / 2; i++) {
|
||||
u32 bt_cur = 0, bt_next = 0;
|
||||
if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_cur = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i];
|
||||
}
|
||||
if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_next = this->ctx->cpu_ctx.aarch32_ctx.stack_trace[i + Aarch32CpuContext::MaxStackTraceDepth / 2];
|
||||
}
|
||||
|
||||
if (i < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("BT[%02X]: ", i);
|
||||
FontManager::SetPosition(x + 76, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%08x ", bt_cur);
|
||||
}
|
||||
|
||||
if (i + Aarch32CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("BT[%02X]: ", i + Aarch32CpuContext::MaxStackTraceDepth / 2);
|
||||
FontManager::SetPosition(x + 76, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%08x ", bt_next);
|
||||
}
|
||||
|
||||
FontManager::PrintLine("");
|
||||
FontManager::SetPosition(backtrace_x, FontManager::GetY());
|
||||
}
|
||||
} else {
|
||||
FontManager::PrintFormatLine("Backtrace (Start Address = 0x%016lx)", this->ctx->cpu_ctx.aarch64_ctx.start_address);
|
||||
FontManager::AddSpacingLines(0.5f);
|
||||
for (u32 i = 0; i < Aarch64CpuContext::MaxStackTraceDepth / 2; i++) {
|
||||
u64 bt_cur = 0, bt_next = 0;
|
||||
if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_cur = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i];
|
||||
}
|
||||
if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_next = this->ctx->cpu_ctx.aarch64_ctx.stack_trace[i + Aarch64CpuContext::MaxStackTraceDepth / 2];
|
||||
}
|
||||
|
||||
if (i < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("BT[%02X]: ", i);
|
||||
FontManager::SetPosition(x + 76, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%016lx ", bt_cur);
|
||||
}
|
||||
|
||||
if (i + Aarch64CpuContext::MaxStackTraceDepth / 2 < this->ctx->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
u32 x = FontManager::GetX();
|
||||
FontManager::PrintFormat("BT[%02X]: ", i + Aarch64CpuContext::MaxStackTraceDepth / 2);
|
||||
FontManager::SetPosition(x + 76, FontManager::GetY());
|
||||
FontManager::PrintFormat("0x%016lx ", bt_next);
|
||||
}
|
||||
|
||||
FontManager::PrintLine("");
|
||||
FontManager::SetPosition(backtrace_x, FontManager::GetY());
|
||||
}
|
||||
}
|
||||
|
||||
/* Enqueue the buffer. */
|
||||
framebufferEnd(&fb);
|
||||
|
|
|
@ -26,13 +26,16 @@ enum FatalResult : Result {
|
|||
FatalResult_InRepairWithoutTimeReviserCartridge = 0xCA3,
|
||||
};
|
||||
|
||||
static constexpr size_t NumAarch64Gprs = 32;
|
||||
static constexpr size_t NumAarch32Gprs = 16;
|
||||
|
||||
struct Aarch64CpuContext {
|
||||
using RegisterType = u64;
|
||||
static constexpr size_t MaxStackTraceDepth = 0x20;
|
||||
|
||||
/* Registers, exception context. N left names for these fields in fatal .rodata. */
|
||||
union {
|
||||
RegisterType x[31];
|
||||
RegisterType x[NumAarch64Gprs];
|
||||
struct {
|
||||
RegisterType _x[29];
|
||||
RegisterType fp;
|
||||
|
@ -60,9 +63,9 @@ struct Aarch32CpuContext {
|
|||
|
||||
/* Registers, exception context. N left names for these fields in fatal .rodata. */
|
||||
union {
|
||||
RegisterType r[16];
|
||||
RegisterType r[NumAarch32Gprs];
|
||||
struct {
|
||||
RegisterType _x[11];
|
||||
RegisterType _r[11];
|
||||
RegisterType fp;
|
||||
RegisterType ip;
|
||||
RegisterType sp;
|
||||
|
@ -86,7 +89,7 @@ struct Aarch32CpuContext {
|
|||
struct FatalCpuContext {
|
||||
union {
|
||||
Aarch64CpuContext aarch64_ctx;
|
||||
Aarch64CpuContext aarch32_ctx;
|
||||
Aarch32CpuContext aarch32_ctx;
|
||||
};
|
||||
|
||||
bool is_aarch32;
|
||||
|
@ -102,3 +105,58 @@ static_assert(sizeof(Aarch64CpuContext) == 0x248, "Aarch64CpuContext definition!
|
|||
static_assert(sizeof(Aarch32CpuContext) == 0xE0, "Aarch32CpuContext definition!");
|
||||
static_assert(sizeof(FatalCpuContext) == 0x250, "FatalCpuContext definition!");
|
||||
static_assert(std::is_pod_v<FatalCpuContext>, "FatalCpuContext definition!");
|
||||
|
||||
static constexpr const char *Aarch64GprNames[NumAarch64Gprs] = {
|
||||
u8"X0",
|
||||
u8"X1",
|
||||
u8"X2",
|
||||
u8"X3",
|
||||
u8"X4",
|
||||
u8"X5",
|
||||
u8"X6",
|
||||
u8"X7",
|
||||
u8"X8",
|
||||
u8"X9",
|
||||
u8"X10",
|
||||
u8"X11",
|
||||
u8"X12",
|
||||
u8"X13",
|
||||
u8"X14",
|
||||
u8"X15",
|
||||
u8"X16",
|
||||
u8"X17",
|
||||
u8"X18",
|
||||
u8"X19",
|
||||
u8"X20",
|
||||
u8"X22",
|
||||
u8"X23",
|
||||
u8"X24",
|
||||
u8"X25",
|
||||
u8"X26",
|
||||
u8"X27",
|
||||
u8"X28",
|
||||
u8"FP",
|
||||
u8"LR",
|
||||
u8"SP",
|
||||
u8"PC",
|
||||
};
|
||||
|
||||
static constexpr const char *Aarch32GprNames[NumAarch32Gprs] = {
|
||||
u8"R0",
|
||||
u8"R1",
|
||||
u8"R2",
|
||||
u8"R3",
|
||||
u8"R4",
|
||||
u8"R5",
|
||||
u8"R6",
|
||||
u8"R7",
|
||||
u8"R8",
|
||||
u8"R9",
|
||||
u8"R10",
|
||||
u8"FP",
|
||||
u8"IP",
|
||||
u8"LR",
|
||||
u8"SP",
|
||||
u8"PC",
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue