Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable debugger / breakpoints / stepping on ARM / ARM64 #11148

Merged
merged 9 commits into from
Jun 7, 2018
94 changes: 52 additions & 42 deletions Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ void Core_NotifyLifecycle(CoreLifecycle stage) {

void Core_Stop() {
Core_UpdateState(CORE_POWERDOWN);
m_StepCond.notify_all();
}

bool Core_IsStepping() {
Expand All @@ -102,6 +101,14 @@ bool Core_IsInactive() {
return coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && !coreStatePending;
}

static inline void Core_StateProcessed() {
if (coreStatePending) {
std::lock_guard<std::mutex> guard(m_hInactiveMutex);
coreStatePending = false;
m_InactiveCond.notify_all();
}
}

void Core_WaitInactive() {
while (Core_IsActive()) {
std::unique_lock<std::mutex> guard(m_hInactiveMutex);
Expand Down Expand Up @@ -173,6 +180,7 @@ bool UpdateScreenScale(int width, int height) {
return false;
}

// Note: not used on Android.
void UpdateRunLoop() {
if (windowHidden && g_Config.bPauseWhenMinimized) {
sleep_ms(16);
Expand All @@ -191,6 +199,8 @@ void KeepScreenAwake() {
void Core_RunLoop(GraphicsContext *ctx) {
graphicsContext = ctx;
while ((GetUIState() != UISTATE_INGAME || !PSP_IsInited()) && GetUIState() != UISTATE_EXIT) {
// In case it was pending, we're not in game anymore. We won't get to Core_Run().
Core_StateProcessed();
time_update();
double startTime = time_now_d();
UpdateRunLoop();
Expand Down Expand Up @@ -227,22 +237,55 @@ void Core_RunLoop(GraphicsContext *ctx) {
}

void Core_DoSingleStep() {
std::lock_guard<std::mutex> guard(m_hStepMutex);
singleStepPending = true;
m_StepCond.notify_all();
}

void Core_UpdateSingleStep() {
std::lock_guard<std::mutex> guard(m_hStepMutex);
m_StepCond.notify_all();
}

void Core_SingleStep() {
currentMIPS->SingleStep();
if (coreState == CORE_STEPPING)
steppingCounter++;
}

static inline void CoreStateProcessed() {
if (coreStatePending) {
coreStatePending = false;
m_InactiveCond.notify_all();
static inline bool Core_WaitStepping() {
std::unique_lock<std::mutex> guard(m_hStepMutex);
if (!singleStepPending && coreState == CORE_STEPPING)
m_StepCond.wait(guard);

bool result = singleStepPending;
singleStepPending = false;
return result;
}

void Core_ProcessStepping() {
Core_StateProcessed();

// Check if there's any pending save state actions.
SaveState::Process();
if (coreState != CORE_STEPPING) {
return;
}

// We're not inside jit now, so it's safe to clear the breakpoints.
CBreakPoints::ClearTemporaryBreakPoints();
host->UpdateDisassembly();
host->UpdateMemView();

// Need to check inside the lock to avoid races.
bool doStep = Core_WaitStepping();

// We may still be stepping without singleStepPending to process a save state.
if (doStep && coreState == CORE_STEPPING) {
Core_SingleStep();
// Update disasm dialog.
host->UpdateDisassembly();
host->UpdateMemView();
}
}

Expand All @@ -251,9 +294,8 @@ static inline void CoreStateProcessed() {
void Core_Run(GraphicsContext *ctx) {
host->UpdateDisassembly();
while (true) {
reswitch:
if (GetUIState() != UISTATE_INGAME) {
CoreStateProcessed();
Core_StateProcessed();
if (GetUIState() == UISTATE_EXIT) {
UpdateRunLoop();
return;
Expand All @@ -264,51 +306,20 @@ void Core_Run(GraphicsContext *ctx) {

switch (coreState) {
case CORE_RUNNING:
case CORE_STEPPING:
// enter a fast runloop
Core_RunLoop(ctx);
break;

// We should never get here on Android.
case CORE_STEPPING:
singleStepPending = false;
CoreStateProcessed();

// Check if there's any pending savestate actions.
SaveState::Process();
if (coreState == CORE_POWERDOWN) {
Core_StateProcessed();
return;
}

// wait for step command..
host->UpdateDisassembly();
host->UpdateMemView();
host->SendCoreWait(true);

{
std::unique_lock<std::mutex> guard(m_hStepMutex);
m_StepCond.wait(guard);
}

host->SendCoreWait(false);
// No step pending? Let's go back to the wait.
if (!singleStepPending || coreState != CORE_STEPPING) {
if (coreState == CORE_POWERDOWN) {
return;
}
goto reswitch;
}

Core_SingleStep();
// update disasm dialog
host->UpdateDisassembly();
host->UpdateMemView();
break;

case CORE_POWERUP:
case CORE_POWERDOWN:
case CORE_ERROR:
// Exit loop!!
CoreStateProcessed();
Core_StateProcessed();

return;

Expand All @@ -320,7 +331,6 @@ void Core_Run(GraphicsContext *ctx) {

void Core_EnableStepping(bool step) {
if (step) {
sleep_ms(1);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! :)

host->SetDebugMode(true);
Core_UpdateState(CORE_STEPPING);
steppingCounter++;
Expand Down
2 changes: 2 additions & 0 deletions Core/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void Core_SetGraphicsContext(GraphicsContext *ctx);
void Core_EnableStepping(bool step);
void Core_DoSingleStep();
void Core_UpdateSingleStep();
void Core_ProcessStepping();
// Changes every time we enter stepping.
int Core_GetSteppingCounter();

Expand All @@ -54,6 +55,7 @@ bool Core_IsStepping();

bool Core_IsActive();
bool Core_IsInactive();
// Warning: these currently work only on Windows.
void Core_WaitInactive();
void Core_WaitInactive(int milliseconds);

Expand Down
26 changes: 12 additions & 14 deletions Core/Debugger/Breakpoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ u64 CBreakPoints::breakSkipFirstTicks_ = 0;
std::vector<MemCheck> CBreakPoints::memChecks_;
std::vector<MemCheck *> CBreakPoints::cleanupMemChecks_;

MemCheck::MemCheck()
{
numHits = 0;
}

void MemCheck::Log(u32 addr, bool write, int size, u32 pc) {
if (result & BREAK_ACTION_LOG) {
if (logFormat.empty()) {
Expand Down Expand Up @@ -493,17 +488,20 @@ u32 CBreakPoints::CheckSkipFirst()
return 0;
}

const std::vector<MemCheck> CBreakPoints::GetMemCheckRanges()
{
const std::vector<MemCheck> CBreakPoints::GetMemCheckRanges(bool write) {
std::vector<MemCheck> ranges = memChecks_;
for (auto it = memChecks_.begin(), end = memChecks_.end(); it != end; ++it)
{
MemCheck check = *it;
for (const auto &check : memChecks_) {
if (!(check.cond & MEMCHECK_READ) && !write)
continue;
if (!(check.cond & MEMCHECK_WRITE) && write)
continue;

MemCheck copy = check;
// Toggle the cached part of the address.
check.start ^= 0x40000000;
if (check.end != 0)
check.end ^= 0x40000000;
ranges.push_back(check);
copy.start ^= 0x40000000;
if (copy.end != 0)
copy.end ^= 0x40000000;
ranges.push_back(copy);
}

return ranges;
Expand Down
48 changes: 18 additions & 30 deletions Core/Debugger/Breakpoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@

#include "Core/Debugger/DebugInterface.h"

enum BreakAction
{
enum BreakAction {
BREAK_ACTION_IGNORE = 0x00,
BREAK_ACTION_LOG = 0x01,
BREAK_ACTION_PAUSE = 0x02,
Expand All @@ -37,35 +36,27 @@ static inline BreakAction operator | (const BreakAction &lhs, const BreakAction
return BreakAction((u32)lhs | (u32)rhs);
}

struct BreakPointCond
{
DebugInterface *debug;
struct BreakPointCond {
DebugInterface *debug = nullptr;
PostfixExpression expression;
std::string expressionString;

BreakPointCond() : debug(nullptr)
{
}

u32 Evaluate()
{
u32 Evaluate() {
u32 result;
if (debug->parseExpression(expression,result) == false) return 0;
if (debug->parseExpression(expression, result) == false)
return 0;
return result;
}
};

struct BreakPoint
{
BreakPoint() : hasCond(false) {}

struct BreakPoint {
u32 addr;
bool temporary;

BreakAction result;
BreakAction result = BREAK_ACTION_IGNORE;
std::string logFormat;

bool hasCond;
bool hasCond = false;
BreakPointCond cond;

bool IsEnabled() const {
Expand All @@ -80,30 +71,27 @@ struct BreakPoint
}
};

enum MemCheckCondition
{
enum MemCheckCondition {
MEMCHECK_READ = 0x01,
MEMCHECK_WRITE = 0x02,
MEMCHECK_WRITE_ONCHANGE = 0x04,

MEMCHECK_READWRITE = 0x03,
};

struct MemCheck
{
MemCheck();
struct MemCheck {
u32 start;
u32 end;

MemCheckCondition cond;
BreakAction result;
MemCheckCondition cond = MEMCHECK_READ;
BreakAction result = BREAK_ACTION_IGNORE;
std::string logFormat;

u32 numHits;
u32 numHits = 0;

u32 lastPC;
u32 lastAddr;
int lastSize;
u32 lastPC = 0;
u32 lastAddr = 0;
int lastSize = 0;

BreakAction Action(u32 addr, bool write, int size, u32 pc);
void JitBefore(u32 addr, bool write, int size, u32 pc);
Expand Down Expand Up @@ -168,7 +156,7 @@ class CBreakPoints
static u32 CheckSkipFirst();

// Includes uncached addresses.
static const std::vector<MemCheck> GetMemCheckRanges();
static const std::vector<MemCheck> GetMemCheckRanges(bool write);

static const std::vector<MemCheck> GetMemChecks();
static const std::vector<BreakPoint> GetBreakpoints();
Expand Down
Loading