Plumbing breakpoints down into alloy Debugger interface.

This commit is contained in:
Ben Vanik 2013-12-22 17:50:14 -08:00
parent e45a7afabc
commit 7098ed3b02
8 changed files with 213 additions and 16 deletions

View File

@ -0,0 +1,40 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <alloy/runtime/debugger.h>
using namespace alloy;
using namespace alloy::runtime;
Breakpoint::Breakpoint(Type type, uint64_t address) :
type_(type), address_(address) {
}
Breakpoint::~Breakpoint() {
}
Debugger::Debugger(Runtime* runtime) :
runtime_(runtime) {
}
Debugger::~Debugger() {
}
int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
return 1;
}
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
return 1;
}
int Debugger::RemoveAllBreakpoints() {
return 1;
}

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef ALLOY_RUNTIME_DEBUGGER_H_
#define ALLOY_RUNTIME_DEBUGGER_H_
#include <alloy/core.h>
namespace alloy {
namespace runtime {
class Runtime;
class Breakpoint {
public:
enum Type {
TEMP_TYPE,
CODE_TYPE,
};
public:
Breakpoint(Type type, uint64_t address);
~Breakpoint();
Type type() const { return type_; }
uint64_t address() const { return address_; }
private:
Type type_;
uint64_t address_;
};
class Debugger {
public:
Debugger(Runtime* runtime);
~Debugger();
Runtime* runtime() const { return runtime_; }
int AddBreakpoint(Breakpoint* breakpoint);
int RemoveBreakpoint(Breakpoint* breakpoint);
int RemoveAllBreakpoints();
private:
Runtime* runtime_;
};
} // namespace runtime
} // namespace alloy
#endif // ALLOY_RUNTIME_DEBUGGER_H_

View File

@ -25,7 +25,7 @@ DEFINE_string(runtime_backend, "any",
Runtime::Runtime(Memory* memory) :
memory_(memory), backend_(0), frontend_(0),
memory_(memory), debugger_(0), backend_(0), frontend_(0),
access_callbacks_(0) {
tracing::Initialize();
modules_lock_ = AllocMutex(10000);
@ -51,6 +51,7 @@ Runtime::~Runtime() {
delete frontend_;
delete backend_;
delete debugger_;
tracing::Flush();
}
@ -67,6 +68,9 @@ int Runtime::Initialize(Frontend* frontend, Backend* backend) {
return result;
}
// Create debugger first. Other types hook up to it.
debugger_ = new Debugger(this);
if (frontend_ || backend_) {
return 1;
}

View File

@ -14,6 +14,7 @@
#include <alloy/memory.h>
#include <alloy/backend/backend.h>
#include <alloy/frontend/frontend.h>
#include <alloy/runtime/debugger.h>
#include <alloy/runtime/entry_table.h>
#include <alloy/runtime/module.h>
#include <alloy/runtime/register_access.h>
@ -34,6 +35,7 @@ public:
virtual ~Runtime();
Memory* memory() const { return memory_; }
Debugger* debugger() const { return debugger_; }
frontend::Frontend* frontend() const { return frontend_; }
backend::Backend* backend() const { return backend_; }
RegisterAccessCallbacks* access_callbacks() const {
@ -62,6 +64,8 @@ private:
protected:
Memory* memory_;
Debugger* debugger_;
frontend::Frontend* frontend_;
backend::Backend* backend_;

View File

@ -1,13 +0,0 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'simple_context.cc',
'simple_context.h',
'simple_memory.cc',
'simple_memory.h',
'simple_runtime.cc',
'simple_runtime.h',
'simple_thread_state.cc',
'simple_thread_state.h',
],
}

View File

@ -3,6 +3,8 @@
'sources': [
'debug_info.cc',
'debug_info.h',
'debugger.cc',
'debugger.h',
'entry_table.cc',
'entry_table.h',
'function.cc',
@ -22,6 +24,5 @@
],
'includes': [
#'simple/sources.gypi',
],
}

View File

@ -11,6 +11,7 @@
#include <jansson.h>
#include <alloy/runtime/debugger.h>
#include <xenia/emulator.h>
#include <xenia/cpu/xenon_memory.h>
#include <xenia/cpu/xenon_runtime.h>
@ -55,6 +56,7 @@ Processor::Processor(Emulator* emulator) :
runtime_(0), memory_(emulator->memory()),
interrupt_thread_lock_(NULL), interrupt_thread_state_(NULL),
interrupt_thread_block_(0),
breakpoints_lock_(0),
DebugTarget(emulator->debug_server()) {
InitializeIfNeeded();
@ -64,6 +66,15 @@ Processor::Processor(Emulator* emulator) :
Processor::~Processor() {
emulator_->debug_server()->RemoveTarget("cpu");
xe_mutex_lock(breakpoints_lock_);
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
Breakpoint* breakpoint = it->second;
delete breakpoint;
}
breakpoints_.clear();
xe_mutex_unlock(breakpoints_lock_);
xe_mutex_free(breakpoints_lock_);
if (interrupt_thread_block_) {
memory_->HeapFree(interrupt_thread_block_, 2048);
delete interrupt_thread_state_;
@ -98,6 +109,8 @@ int Processor::Setup() {
0, 2048, MEMORY_FLAG_ZERO);
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
breakpoints_lock_ = xe_mutex_alloc(10000);
return 0;
}
@ -280,12 +293,94 @@ json_t* Processor::OnDebugRequest(
return fn_json;
} else if (xestrcmpa(command, "add_breakpoints") == 0) {
// breakpoints: []
// breakpoints: [{}]
json_t* breakpoints_json = json_object_get(request, "breakpoints");
if (!breakpoints_json || !json_is_array(breakpoints_json)) {
succeeded = false;
return json_string("Breakpoints not specified");
}
if (!json_array_size(breakpoints_json)) {
// No-op;
return json_null();
}
for (size_t n = 0; n < json_array_size(breakpoints_json); n++) {
json_t* breakpoint_json = json_array_get(breakpoints_json, n);
if (!breakpoint_json || !json_is_object(breakpoint_json)) {
succeeded = false;
return json_string("Invalid breakpoint type");
}
json_t* breakpoint_id_json = json_object_get(breakpoint_json, "id");
json_t* type_json = json_object_get(breakpoint_json, "type");
json_t* address_json = json_object_get(breakpoint_json, "address");
if (!breakpoint_id_json || !json_is_string(breakpoint_id_json) ||
!type_json || !json_is_string(type_json) ||
!address_json || !json_is_number(address_json)) {
succeeded = false;
return json_string("Invalid breakpoint members");
}
const char* breakpoint_id = json_string_value(breakpoint_id_json);
const char* type_str = json_string_value(type_json);
uint64_t address = (uint64_t)json_number_value(address_json);
Breakpoint::Type type;
if (xestrcmpa(type_str, "temp") == 0) {
type = Breakpoint::TEMP_TYPE;
} else if (xestrcmpa(type_str, "code") == 0) {
type = Breakpoint::CODE_TYPE;
} else {
succeeded = false;
return json_string("Unknown breakpoint type");
}
Breakpoint* breakpoint = new Breakpoint(
type, address);
xe_mutex_lock(breakpoints_lock_);
breakpoints_[breakpoint_id] = breakpoint;
int result = runtime_->debugger()->AddBreakpoint(breakpoint);
xe_mutex_unlock(breakpoints_lock_);
if (result) {
succeeded = false;
return json_string("Error adding breakpoint");
}
}
return json_null();
} else if (xestrcmpa(command, "remove_breakpoints") == 0) {
// breakpointIds: ['id']
json_t* breakpoint_ids_json = json_object_get(request, "breakpointIds");
if (!breakpoint_ids_json || !json_is_array(breakpoint_ids_json)) {
succeeded = false;
return json_string("Breakpoint IDs not specified");
}
if (!json_array_size(breakpoint_ids_json)) {
// No-op;
return json_null();
}
for (size_t n = 0; n < json_array_size(breakpoint_ids_json); n++) {
json_t* breakpoint_id_json = json_array_get(breakpoint_ids_json, n);
if (!breakpoint_id_json || !json_is_string(breakpoint_id_json)) {
succeeded = false;
return json_string("Invalid breakpoint ID type");
}
const char* breakpoint_id = json_string_value(breakpoint_id_json);
xe_mutex_lock(breakpoints_lock_);
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
if (breakpoint) {
breakpoints_.erase(breakpoint_id);
runtime_->debugger()->RemoveBreakpoint(breakpoint);
delete breakpoint;
}
xe_mutex_unlock(breakpoints_lock_);
}
return json_null();
} else if (xestrcmpa(command, "remove_all_breakpoints") == 0) {
xe_mutex_lock(breakpoints_lock_);
runtime_->debugger()->RemoveAllBreakpoints();
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
Breakpoint* breakpoint = it->second;
delete breakpoint;
}
breakpoints_.clear();
xe_mutex_unlock(breakpoints_lock_);
return json_null();
} else {
succeeded = false;

View File

@ -16,6 +16,7 @@
#include <vector>
XEDECLARECLASS2(alloy, runtime, Breakpoint);
XEDECLARECLASS1(xe, Emulator);
XEDECLARECLASS1(xe, ExportResolver);
XEDECLARECLASS2(xe, cpu, XenonMemory);
@ -69,6 +70,10 @@ private:
xe_mutex_t* interrupt_thread_lock_;
XenonThreadState* interrupt_thread_state_;
uint64_t interrupt_thread_block_;
xe_mutex_t* breakpoints_lock_;
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
BreakpointMap breakpoints_;
};