Permalink
Browse files

Merge pull request #11148 from unknownbrackets/debugger-arm

Enable debugger / breakpoints / stepping on ARM / ARM64
  • Loading branch information...
hrydgard committed Jun 7, 2018
2 parents 3ed9d0b + 4c3fe47 commit e4aef7209f582a0f05bbb20b7da58eac73ca6d2b
View
@@ -87,7 +87,6 @@ void Core_NotifyLifecycle(CoreLifecycle stage) {
void Core_Stop() {
Core_UpdateState(CORE_POWERDOWN);
m_StepCond.notify_all();
}
bool Core_IsStepping() {
@@ -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);
@@ -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);
@@ -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();
@@ -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();
}
}
@@ -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;
@@ -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;
@@ -320,7 +331,6 @@ void Core_Run(GraphicsContext *ctx) {
void Core_EnableStepping(bool step) {
if (step) {
sleep_ms(1);
host->SetDebugMode(true);
Core_UpdateState(CORE_STEPPING);
steppingCounter++;
View
@@ -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();
@@ -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);
@@ -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()) {
@@ -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;
@@ -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,
@@ -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 {
@@ -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);
@@ -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();
Oops, something went wrong.

0 comments on commit e4aef72

Please sign in to comment.