Suspend/resume working.
This commit is contained in:
parent
dc48b0a85a
commit
98efc7ddfa
|
@ -247,7 +247,7 @@ module.controller('FunctionViewController', function(
|
||||||
instance, line, gutterClass, e) {
|
instance, line, gutterClass, e) {
|
||||||
if (e.which == 1) {
|
if (e.which == 1) {
|
||||||
if (gutterClass == 'debugger-fnview-gutter-icon' ||
|
if (gutterClass == 'debugger-fnview-gutter-icon' ||
|
||||||
gutterClsas == 'debugger-fnview-gutter-addr') {
|
gutterClass == 'debugger-fnview-gutter-addr') {
|
||||||
var sourceLine = $scope.sourceLines[line];
|
var sourceLine = $scope.sourceLines[line];
|
||||||
if (!sourceLine || sourceLine[0] != 'i') {
|
if (!sourceLine || sourceLine[0] != 'i') {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -145,9 +145,10 @@ module.service('DataSource', function($q) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
DataSource.prototype.stepNext = function() {
|
DataSource.prototype.stepNext = function(threadId) {
|
||||||
return this.issue({
|
return this.issue({
|
||||||
command: 'cpu.step'
|
command: 'cpu.step',
|
||||||
|
threadId: threadId
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -224,26 +224,31 @@ module.service('Session', function(
|
||||||
};
|
};
|
||||||
|
|
||||||
Session.prototype.onBreakpointHit = function(breakpointId, threadId) {
|
Session.prototype.onBreakpointHit = function(breakpointId, threadId) {
|
||||||
var breakpoint = this.breakpointsById[breakpointId];
|
|
||||||
var thread = null; // TODO
|
|
||||||
if (!breakpoint) {
|
|
||||||
log.error('Breakpoint hit but not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now paused!
|
// Now paused!
|
||||||
this.paused = true;
|
this.paused = true;
|
||||||
|
|
||||||
$state.go('session.code.function', {
|
if (breakpointId) {
|
||||||
'function': breakpoint.fnAddress.toString(16).toUpperCase(),
|
var breakpoint = this.breakpointsById[breakpointId];
|
||||||
'a': breakpoint.address.toString(16).toUpperCase()
|
var thread = null; // TODO
|
||||||
}, {
|
if (!breakpoint) {
|
||||||
notify: false,
|
log.error('Breakpoint hit but not found');
|
||||||
reloadOnSearch: false
|
return;
|
||||||
});
|
}
|
||||||
|
|
||||||
//
|
log.info('Breakpoint hit at 0x' +
|
||||||
log.info('breakpoint!!');
|
breakpoint.address.toString(16).toUpperCase() + '.');
|
||||||
|
|
||||||
|
$state.go('session.code.function', {
|
||||||
|
'function': breakpoint.fnAddress.toString(16).toUpperCase(),
|
||||||
|
'a': breakpoint.address.toString(16).toUpperCase()
|
||||||
|
}, {
|
||||||
|
notify: false,
|
||||||
|
reloadOnSearch: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Just a general pause.
|
||||||
|
log.info('Execution paused.');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Session.prototype.continueExecution = function() {
|
Session.prototype.continueExecution = function() {
|
||||||
|
@ -252,6 +257,7 @@ module.service('Session', function(
|
||||||
}
|
}
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
this.dataSource.continueExecution().then(function() {
|
this.dataSource.continueExecution().then(function() {
|
||||||
|
log.info('Execution resumed.');
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
log.error('Unable to continue: ' + e);
|
log.error('Unable to continue: ' + e);
|
||||||
});
|
});
|
||||||
|
@ -261,18 +267,20 @@ module.service('Session', function(
|
||||||
if (!this.dataSource) {
|
if (!this.dataSource) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.paused = true;
|
||||||
this.dataSource.breakExecution().then(function() {
|
this.dataSource.breakExecution().then(function() {
|
||||||
|
log.info('Execution paused.');
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
log.error('Unable to break: ' + e);
|
log.error('Unable to break: ' + e);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Session.prototype.stepNext = function() {
|
Session.prototype.stepNext = function(threadId) {
|
||||||
if (!this.dataSource) {
|
if (!this.dataSource) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
this.dataSource.breakExecution().then(function() {
|
this.dataSource.stepNext(threadId).then(function() {
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
log.error('Unable to step: ' + e);
|
log.error('Unable to step: ' + e);
|
||||||
});
|
});
|
||||||
|
|
|
@ -119,11 +119,19 @@ int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) {
|
||||||
ics.return_address = return_address;
|
ics.return_address = return_address;
|
||||||
ics.call_return_address = 0;
|
ics.call_return_address = 0;
|
||||||
|
|
||||||
|
volatile int* suspend_flag_address = thread_state->suspend_flag_address();
|
||||||
|
|
||||||
// TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY
|
// TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY
|
||||||
// or something so the fns can set an ics flag.
|
// or something so the fns can set an ics flag.
|
||||||
|
|
||||||
uint32_t ia = 0;
|
uint32_t ia = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Check suspend. We could do this only on certain instructions, if we
|
||||||
|
// wanted to speed things up.
|
||||||
|
if (*suspend_flag_address) {
|
||||||
|
thread_state->EnterSuspend();
|
||||||
|
}
|
||||||
|
|
||||||
IntCode* i = &intcodes_[ia];
|
IntCode* i = &intcodes_[ia];
|
||||||
|
|
||||||
if (i->debug_flags) {
|
if (i->debug_flags) {
|
||||||
|
|
|
@ -190,7 +190,7 @@ typedef struct XECACHEALIGN64 PPCContext_s {
|
||||||
uint8_t* membase;
|
uint8_t* membase;
|
||||||
runtime::Runtime* runtime;
|
runtime::Runtime* runtime;
|
||||||
runtime::ThreadState* thread_state;
|
runtime::ThreadState* thread_state;
|
||||||
uint32_t suspend_flag;
|
volatile int suspend_flag;
|
||||||
|
|
||||||
void SetRegFromString(const char* name, const char* value);
|
void SetRegFromString(const char* name, const char* value);
|
||||||
bool CompareRegWithString(const char* name, const char* value,
|
bool CompareRegWithString(const char* name, const char* value,
|
||||||
|
|
|
@ -63,12 +63,12 @@ int Debugger::ResumeThread(uint32_t thread_id) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Debugger::ResumeAllThreads() {
|
int Debugger::ResumeAllThreads(bool force) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
LockMutex(threads_lock_);
|
LockMutex(threads_lock_);
|
||||||
for (auto it = threads_.begin(); it != threads_.end(); ++it) {
|
for (auto it = threads_.begin(); it != threads_.end(); ++it) {
|
||||||
ThreadState* thread_state = it->second;
|
ThreadState* thread_state = it->second;
|
||||||
if (thread_state->Resume()) {
|
if (thread_state->Resume(force)) {
|
||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ public:
|
||||||
|
|
||||||
int SuspendAllThreads(uint32_t timeout_ms = UINT_MAX);
|
int SuspendAllThreads(uint32_t timeout_ms = UINT_MAX);
|
||||||
int ResumeThread(uint32_t thread_id);
|
int ResumeThread(uint32_t thread_id);
|
||||||
int ResumeAllThreads();
|
int ResumeAllThreads(bool force = false);
|
||||||
|
|
||||||
int AddBreakpoint(Breakpoint* breakpoint);
|
int AddBreakpoint(Breakpoint* breakpoint);
|
||||||
int RemoveBreakpoint(Breakpoint* breakpoint);
|
int RemoveBreakpoint(Breakpoint* breakpoint);
|
||||||
|
|
|
@ -32,8 +32,10 @@ public:
|
||||||
void* backend_data() const { return backend_data_; }
|
void* backend_data() const { return backend_data_; }
|
||||||
void* raw_context() const { return raw_context_; }
|
void* raw_context() const { return raw_context_; }
|
||||||
|
|
||||||
|
virtual volatile int* suspend_flag_address() const = 0;
|
||||||
virtual int Suspend(uint32_t timeout_ms = UINT_MAX) = 0;
|
virtual int Suspend(uint32_t timeout_ms = UINT_MAX) = 0;
|
||||||
virtual int Resume() = 0;
|
virtual int Resume(bool force = false) = 0;
|
||||||
|
virtual void EnterSuspend() = 0;
|
||||||
|
|
||||||
static void Bind(ThreadState* thread_state);
|
static void Bind(ThreadState* thread_state);
|
||||||
static ThreadState* Get();
|
static ThreadState* Get();
|
||||||
|
|
|
@ -218,6 +218,10 @@ void Processor::OnDebugClientDisconnected(uint32_t client_id) {
|
||||||
debug_client_states_.erase(client_id);
|
debug_client_states_.erase(client_id);
|
||||||
xe_mutex_unlock(debug_client_states_lock_);
|
xe_mutex_unlock(debug_client_states_lock_);
|
||||||
delete client_state;
|
delete client_state;
|
||||||
|
|
||||||
|
// Whenever we support multiple clients we will need to respect pause
|
||||||
|
// settings. For now, resume until running.
|
||||||
|
runtime_->debugger()->ResumeAllThreads(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_t* Processor::OnDebugRequest(
|
json_t* Processor::OnDebugRequest(
|
||||||
|
@ -417,6 +421,21 @@ json_t* Processor::OnDebugRequest(
|
||||||
return json_string("Unable to remove breakpoints");
|
return json_string("Unable to remove breakpoints");
|
||||||
}
|
}
|
||||||
return json_null();
|
return json_null();
|
||||||
|
} else if (xestrcmpa(command, "continue") == 0) {
|
||||||
|
if (runtime_->debugger()->ResumeAllThreads()) {
|
||||||
|
succeeded = false;
|
||||||
|
return json_string("Unable to resume threads");
|
||||||
|
}
|
||||||
|
return json_null();
|
||||||
|
} else if (xestrcmpa(command, "break") == 0) {
|
||||||
|
if (runtime_->debugger()->SuspendAllThreads()) {
|
||||||
|
succeeded = false;
|
||||||
|
return json_string("Unable to suspend threads");
|
||||||
|
}
|
||||||
|
return json_null();
|
||||||
|
} else if (xestrcmpa(command, "step") == 0) {
|
||||||
|
// threadId
|
||||||
|
return json_null();
|
||||||
} else {
|
} else {
|
||||||
succeeded = false;
|
succeeded = false;
|
||||||
return json_string("Unknown command");
|
return json_string("Unknown command");
|
||||||
|
|
|
@ -28,6 +28,8 @@ XenonThreadState::XenonThreadState(
|
||||||
stack_address_ = memory_->HeapAlloc(
|
stack_address_ = memory_->HeapAlloc(
|
||||||
0, stack_size, MEMORY_FLAG_ZERO);
|
0, stack_size, MEMORY_FLAG_ZERO);
|
||||||
|
|
||||||
|
debug_break_ = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
// Allocate with 64b alignment.
|
// Allocate with 64b alignment.
|
||||||
context_ = (PPCContext*)xe_malloc_aligned(sizeof(PPCContext));
|
context_ = (PPCContext*)xe_malloc_aligned(sizeof(PPCContext));
|
||||||
XEASSERT(((uint64_t)context_ & 0xF) == 0);
|
XEASSERT(((uint64_t)context_ & 0xF) == 0);
|
||||||
|
@ -53,6 +55,8 @@ XenonThreadState::XenonThreadState(
|
||||||
XenonThreadState::~XenonThreadState() {
|
XenonThreadState::~XenonThreadState() {
|
||||||
runtime_->debugger()->OnThreadDestroyed(this);
|
runtime_->debugger()->OnThreadDestroyed(this);
|
||||||
|
|
||||||
|
CloseHandle(debug_break_);
|
||||||
|
|
||||||
alloy::tracing::WriteEvent(EventType::ThreadDeinit({
|
alloy::tracing::WriteEvent(EventType::ThreadDeinit({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -60,10 +64,31 @@ XenonThreadState::~XenonThreadState() {
|
||||||
memory_->HeapFree(stack_address_, stack_size_);
|
memory_->HeapFree(stack_address_, stack_size_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volatile int* XenonThreadState::suspend_flag_address() const {
|
||||||
|
return &context_->suspend_flag;
|
||||||
|
}
|
||||||
|
|
||||||
int XenonThreadState::Suspend(uint32_t timeout_ms) {
|
int XenonThreadState::Suspend(uint32_t timeout_ms) {
|
||||||
|
// Set suspend flag.
|
||||||
|
// One of the checks should call in to OnSuspend() at some point.
|
||||||
|
xe_atomic_inc_32(&context_->suspend_flag);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XenonThreadState::Resume() {
|
int XenonThreadState::Resume(bool force) {
|
||||||
|
if (context_->suspend_flag) {
|
||||||
|
if (force) {
|
||||||
|
context_->suspend_flag = 0;
|
||||||
|
SetEvent(debug_break_);
|
||||||
|
} else {
|
||||||
|
if (!xe_atomic_dec_32(&context_->suspend_flag)) {
|
||||||
|
SetEvent(debug_break_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XenonThreadState::EnterSuspend() {
|
||||||
|
WaitForSingleObject(debug_break_, INFINITE);
|
||||||
|
}
|
||||||
|
|
|
@ -31,8 +31,10 @@ public:
|
||||||
|
|
||||||
PPCContext* context() const { return context_; }
|
PPCContext* context() const { return context_; }
|
||||||
|
|
||||||
|
virtual volatile int* suspend_flag_address() const;
|
||||||
virtual int Suspend(uint32_t timeout_ms = UINT_MAX);
|
virtual int Suspend(uint32_t timeout_ms = UINT_MAX);
|
||||||
virtual int Resume();
|
virtual int Resume(bool force = false);
|
||||||
|
virtual void EnterSuspend();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t stack_size_;
|
size_t stack_size_;
|
||||||
|
@ -44,6 +46,8 @@ private:
|
||||||
|
|
||||||
// NOTE: must be 64b aligned for SSE ops.
|
// NOTE: must be 64b aligned for SSE ops.
|
||||||
PPCContext* context_;
|
PPCContext* context_;
|
||||||
|
|
||||||
|
HANDLE debug_break_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue