libstrat: Custom exception handlers/std::abort

This commit is contained in:
Michael Scire 2019-04-12 15:26:27 -07:00
parent 1f9e2d042c
commit b9724cdcad
5 changed files with 233 additions and 1 deletions

View File

@ -37,4 +37,6 @@
#include "stratosphere/results.hpp"
#include "stratosphere/title_ids.hpp"
#include "stratosphere/title_ids.hpp"
#include "stratosphere/on_crash.hpp"

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <cstdlib>
#include "services/bpc_ams.h"
static constexpr size_t AtmosphereFatalErrorNumGprs = 29;
static constexpr u32 AtmosphereFatalErrorMagic = 0x30454641; /* "AFE0" */
/* Will be called by libstratosphere on crash. */
void StratosphereCrashHandler(ThreadExceptionDump *ctx);

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
u32 magic;
u32 error_desc;
u64 title_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 padding;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
} AtmosphereFatalErrorContext;
Result bpcAmsInitialize(void);
void bpcAmsExit(void);
Result bpcAmsRebootToFatalError(AtmosphereFatalErrorContext *ctx);
#ifdef __cplusplus
}
#endif

76
source/bpc_ams.c Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <switch/arm/atomics.h>
#include <stratosphere/services/bpc_ams.h>
static Service g_bpcAmsSrv;
static u64 g_bpcAmsAmsRefcnt;
Result bpcAmsInitialize(void) {
atomicIncrement64(&g_bpcAmsAmsRefcnt);
if (serviceIsActive(&g_bpcAmsSrv)) {
return 0;
}
Handle h;
Result rc = svcConnectToNamedPort(&h, "bpc:ams");
if (R_SUCCEEDED(rc)) {
serviceCreate(&g_bpcAmsSrv, h);
}
return rc;
}
void bpcAmsExit(void) {
if (atomicDecrement64(&g_bpcAmsAmsRefcnt) == 0)
serviceClose(&g_bpcAmsSrv);
}
Result bpcAmsRebootToFatalError(AtmosphereFatalErrorContext *ctx) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, ctx, sizeof(*ctx), BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(&g_bpcAmsSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 65000;
Result rc = serviceIpcDispatch(&g_bpcAmsSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_bpcAmsSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}

73
source/on_crash.cpp Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mutex>
#include <switch.h>
#include <stratosphere.hpp>
extern "C" {
__attribute__((weak)) u64 __stratosphere_title_id = 0;
void __attribute__((weak)) __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx);
/* Redefine abort, so that it triggers these handlers. */
void abort();
};
void StratosphereCrashHandler(ThreadExceptionDump *ctx) {
AtmosphereFatalErrorContext ams_ctx;
/* Convert thread dump to atmosphere dump. */
{
ams_ctx.magic = AtmosphereFatalErrorMagic;
ams_ctx.error_desc = ctx->error_desc;
ams_ctx.title_id = __stratosphere_title_id;
for (size_t i = 0; i < AtmosphereFatalErrorNumGprs; i++) {
ams_ctx.gprs[i] = ctx->cpu_gprs[i].x;
}
ams_ctx.fp = ctx->fp.x;
ams_ctx.lr = ctx->lr.x;
ams_ctx.sp = ctx->sp.x;
ams_ctx.pc = ctx->pc.x;
ams_ctx.pstate = ctx->pstate;
ams_ctx.afsr0 = ctx->afsr0;
ams_ctx.afsr1 = ctx->afsr1;
ams_ctx.far = ctx->far.x;
ams_ctx.report_identifier = armGetSystemTick();
}
/* Just call the user exception handler. */
__libstratosphere_exception_handler(&ams_ctx);
}
/* Default exception handler behavior. */
void __attribute__((weak)) __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
Result rc = bpcAmsInitialize();
if (R_SUCCEEDED(rc)) {
rc = bpcAmsRebootToFatalError(ctx);
bpcAmsExit();
}
if (R_FAILED(rc)) {
std::abort();
}
while (1) { }
}
/* Custom abort handler, so that std::abort will trigger these. */
void abort() {
/* Just perform a data abort. */
while (true) {
*((volatile u64 *)0x8) = 0xCAFEBABE;
}
}