mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Crash screen: Add a very dangerous and inaccurate "Resume" function.
Not sure if there's much point really but maybe..
This commit is contained in:
parent
a550aacf96
commit
6c8ee35826
4 changed files with 56 additions and 7 deletions
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "Common/MachineContext.h"
|
||||
|
||||
#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86)
|
||||
|
@ -37,9 +40,13 @@
|
|||
namespace Memory {
|
||||
|
||||
static int64_t g_numReportedBadAccesses = 0;
|
||||
const uint8_t *g_lastCrashAddress;
|
||||
std::unordered_set<const uint8_t *> g_ignoredAddresses;
|
||||
|
||||
void MemFault_Init() {
|
||||
g_numReportedBadAccesses = 0;
|
||||
g_lastCrashAddress = nullptr;
|
||||
g_ignoredAddresses.clear();
|
||||
}
|
||||
|
||||
#ifdef MACHINE_CONTEXT_SUPPORTED
|
||||
|
@ -67,10 +74,21 @@ static bool DisassembleNativeAt(const uint8_t *codePtr, int instructionSize, std
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MemFault_MayBeResumable() {
|
||||
return g_lastCrashAddress != nullptr;
|
||||
}
|
||||
|
||||
void MemFault_IgnoreLastCrash() {
|
||||
g_ignoredAddresses.insert(g_lastCrashAddress);
|
||||
}
|
||||
|
||||
bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
||||
SContext *context = (SContext *)ctx;
|
||||
const uint8_t *codePtr = (uint8_t *)(context->CTX_PC);
|
||||
|
||||
// We set this later if we think it can be resumed from.
|
||||
g_lastCrashAddress = nullptr;
|
||||
|
||||
// TODO: Check that codePtr is within the current JIT space.
|
||||
bool inJitSpace = MIPSComp::jit && MIPSComp::jit->CodeInRange(codePtr);
|
||||
if (!inJitSpace) {
|
||||
|
@ -91,6 +109,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
// OK, a guest executable did a bad access. Take care of it.
|
||||
|
||||
uint32_t guestAddress = hostAddress - baseAddress;
|
||||
|
@ -149,7 +168,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
|||
type = MemoryExceptionType::UNKNOWN;
|
||||
}
|
||||
|
||||
if (success && g_Config.bIgnoreBadMemAccess) {
|
||||
if (success && (g_Config.bIgnoreBadMemAccess || g_ignoredAddresses.find(codePtr) != g_ignoredAddresses.end())) {
|
||||
if (!info.isMemoryWrite) {
|
||||
// It was a read. Fill the destination register with 0.
|
||||
// TODO
|
||||
|
@ -165,7 +184,10 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) {
|
|||
uint32_t approximatePC = currentMIPS->pc;
|
||||
Core_MemoryExceptionInfo(guestAddress, approximatePC, type, infoString);
|
||||
|
||||
// Redirect execution to a crash handler that will exit the game immediately.
|
||||
// There's a small chance we can resume from this type of crash.
|
||||
g_lastCrashAddress = codePtr;
|
||||
|
||||
// Redirect execution to a crash handler that will switch to CoreState::CORE_RUNTIME_ERROR immediately.
|
||||
context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler();
|
||||
ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation. Info:\n%s", guestAddress, (void *)hostAddress, infoString.c_str());
|
||||
}
|
||||
|
|
|
@ -6,6 +6,14 @@ namespace Memory {
|
|||
|
||||
void MemFault_Init();
|
||||
|
||||
// Used by the hacky "Resume" button.
|
||||
//
|
||||
// TODO: Add a way to actually resume to the next instruction,
|
||||
// rather than just jumping into the dispatcher again and hoping for the best. That will be
|
||||
// a little tricky though, with per-backend work.
|
||||
bool MemFault_MayBeResumable();
|
||||
void MemFault_IgnoreLastCrash();
|
||||
|
||||
// Called by exception handlers. We simply filter out accesses to PSP RAM and otherwise
|
||||
// just leave it as-is.
|
||||
bool HandleFault(uintptr_t hostAddress, void *context);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "Core/Core.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/KeyMap.h"
|
||||
#include "Core/MemFault.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/System.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
@ -1025,6 +1026,9 @@ void EmuScreen::CreateViews() {
|
|||
if (g_Config.bShowDeveloperMenu) {
|
||||
root_->Add(new Button(dev->T("DevMenu")))->OnClick.Handle(this, &EmuScreen::OnDevTools);
|
||||
}
|
||||
resumeButton_ = root_->Add(new Button(dev->T("Resume"), new AnchorLayoutParams(bounds.centerX(), NONE, NONE, 60, true)));
|
||||
resumeButton_->OnClick.Handle(this, &EmuScreen::OnResume);
|
||||
resumeButton_->SetVisibility(V_GONE);
|
||||
|
||||
cardboardDisableButton_ = root_->Add(new Button(sc->T("Cardboard VR OFF"), new AnchorLayoutParams(bounds.centerX(), NONE, NONE, 30, true)));
|
||||
cardboardDisableButton_->OnClick.Handle(this, &EmuScreen::OnDisableCardboard);
|
||||
|
@ -1135,15 +1139,29 @@ UI::EventReturn EmuScreen::OnDisableCardboard(UI::EventParams ¶ms) {
|
|||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn EmuScreen::OnChat(UI::EventParams& params) {
|
||||
if (chatButtons->GetVisibility() == UI::V_VISIBLE) chatButtons->SetVisibility(UI::V_GONE);
|
||||
UI::EventReturn EmuScreen::OnChat(UI::EventParams ¶ms) {
|
||||
if (chatButtons->GetVisibility() == UI::V_VISIBLE) {
|
||||
chatButtons->SetVisibility(UI::V_GONE);
|
||||
}
|
||||
screenManager()->push(new ChatMenu());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn EmuScreen::OnResume(UI::EventParams ¶ms) {
|
||||
if (coreState == CoreState::CORE_RUNTIME_ERROR) {
|
||||
// Force it!
|
||||
Memory::MemFault_IgnoreLastCrash();
|
||||
coreState = CoreState::CORE_RUNNING;
|
||||
}
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
void EmuScreen::update() {
|
||||
using namespace UI;
|
||||
|
||||
UIScreen::update();
|
||||
onScreenMessagesView_->SetVisibility(g_Config.bShowOnScreenMessages ? UI::Visibility::V_VISIBLE : UI::Visibility::V_GONE);
|
||||
onScreenMessagesView_->SetVisibility(g_Config.bShowOnScreenMessages ? V_VISIBLE : V_GONE);
|
||||
resumeButton_->SetVisibility(coreState == CoreState::CORE_RUNTIME_ERROR && Memory::MemFault_MayBeResumable() ? V_VISIBLE : V_GONE);
|
||||
|
||||
if (bootPending_) {
|
||||
bootGame(gamePath_);
|
||||
|
|
|
@ -49,13 +49,13 @@ public:
|
|||
bool key(const KeyInput &key) override;
|
||||
bool axis(const AxisInput &axis) override;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void CreateViews() override;
|
||||
UI::EventReturn OnDevTools(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnDisableCardboard(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnChat(UI::EventParams ¶ms);
|
||||
UI::EventReturn OnResume(UI::EventParams ¶ms);
|
||||
|
||||
private:
|
||||
void bootGame(const std::string &filename);
|
||||
bool bootAllowStorage(const std::string &filename);
|
||||
void bootComplete();
|
||||
|
@ -105,6 +105,7 @@ private:
|
|||
UI::VisibilityTween *loadingViewVisible_ = nullptr;
|
||||
UI::Spinner *loadingSpinner_ = nullptr;
|
||||
UI::TextView *loadingTextView_ = nullptr;
|
||||
UI::Button *resumeButton_ = nullptr;
|
||||
|
||||
UI::Button *cardboardDisableButton_ = nullptr;
|
||||
OnScreenMessagesView *onScreenMessagesView_ = nullptr;
|
||||
|
|
Loading…
Add table
Reference in a new issue