More plumbing for breakpoints.

This commit is contained in:
Ben Vanik 2013-12-22 22:03:06 -08:00
parent 5e9a2c6d27
commit 5881a58c49
10 changed files with 194 additions and 0 deletions

View File

@ -34,6 +34,14 @@ void IVMFunction::Setup(TranslationContext& ctx) {
intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents(); intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents();
} }
int IVMFunction::AddBreakpointImpl(Breakpoint* breakpoint) {
return 0;
}
int IVMFunction::RemoveBreakpointImpl(Breakpoint* breakpoint) {
return 0;
}
int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) { int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) {
// Setup register file on stack. // Setup register file on stack.
size_t register_file_size = register_count_ * sizeof(Register); size_t register_file_size = register_count_ * sizeof(Register);

View File

@ -29,6 +29,8 @@ public:
void Setup(TranslationContext& ctx); void Setup(TranslationContext& ctx);
protected: protected:
virtual int AddBreakpointImpl(runtime::Breakpoint* breakpoint);
virtual int RemoveBreakpointImpl(runtime::Breakpoint* breakpoint);
virtual int CallImpl(runtime::ThreadState* thread_state, virtual int CallImpl(runtime::ThreadState* thread_state,
uint64_t return_address); uint64_t return_address);

View File

@ -9,6 +9,9 @@
#include <alloy/runtime/debugger.h> #include <alloy/runtime/debugger.h>
#include <alloy/mutex.h>
#include <alloy/runtime/runtime.h>
using namespace alloy; using namespace alloy;
using namespace alloy::runtime; using namespace alloy::runtime;
@ -22,15 +25,109 @@ Breakpoint::~Breakpoint() {
Debugger::Debugger(Runtime* runtime) : Debugger::Debugger(Runtime* runtime) :
runtime_(runtime) { runtime_(runtime) {
breakpoints_lock_ = AllocMutex();
} }
Debugger::~Debugger() { Debugger::~Debugger() {
FreeMutex(breakpoints_lock_);
} }
int Debugger::AddBreakpoint(Breakpoint* breakpoint) { int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
// Add to breakpoints map.
LockMutex(breakpoints_lock_);
breakpoints_.insert(
std::pair<uint64_t, Breakpoint*>(breakpoint->address(), breakpoint));
UnlockMutex(breakpoints_lock_);
// Find all functions that contain the breakpoint address.
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
// Add.
for (auto it = fns.begin(); it != fns.end(); ++it) {
Function* fn = *it;
if (fn->AddBreakpoint(breakpoint)) {
return 1;
}
}
return 0; return 0;
} }
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) { int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
// Remove from breakpoint map.
LockMutex(breakpoints_lock_);
auto range = breakpoints_.equal_range(breakpoint->address());
if (range.first == range.second) {
UnlockMutex(breakpoints_lock_);
return 1;
}
bool found = false;
for (auto it = range.first; it != range.second; ++it) {
if (it->second == breakpoint) {
breakpoints_.erase(it);
found = true;
break;
}
}
UnlockMutex(breakpoints_lock_);
if (!found) {
return 1;
}
// Find all functions that have the breakpoint set.
auto fns = runtime_->FindFunctionsWithAddress(breakpoint->address());
// Remove.
for (auto it = fns.begin(); it != fns.end(); ++it) {
Function* fn = *it;
fn->RemoveBreakpoint(breakpoint);
}
return 0; return 0;
} }
void Debugger::FindBreakpoints(
uint64_t address, std::vector<Breakpoint*>& out_breakpoints) {
out_breakpoints.clear();
LockMutex(breakpoints_lock_);
auto range = breakpoints_.equal_range(address);
if (range.first == range.second) {
UnlockMutex(breakpoints_lock_);
return;
}
for (auto it = range.first; it != range.second; ++it) {
Breakpoint* breakpoint = it->second;
out_breakpoints.push_back(breakpoint);
}
UnlockMutex(breakpoints_lock_);
}
void Debugger::OnFunctionDefined(FunctionInfo* symbol_info,
Function* function) {
// Man, I'd love not to take this lock.
std::vector<Breakpoint*> breakpoints;
LockMutex(breakpoints_lock_);
for (uint64_t address = symbol_info->address();
address <= symbol_info->end_address(); address += 4) {
auto range = breakpoints_.equal_range(address);
if (range.first == range.second) {
continue;
}
for (auto it = range.first; it != range.second; ++it) {
Breakpoint* breakpoint = it->second;
breakpoints.push_back(breakpoint);
}
}
UnlockMutex(breakpoints_lock_);
if (breakpoints.size()) {
// Breakpoints to add!
for (auto it = breakpoints.begin(); it != breakpoints.end(); ++it) {
function->AddBreakpoint(*it);
}
}
}

View File

@ -12,10 +12,14 @@
#include <alloy/core.h> #include <alloy/core.h>
#include <map>
namespace alloy { namespace alloy {
namespace runtime { namespace runtime {
class Function;
class FunctionInfo;
class Runtime; class Runtime;
@ -47,9 +51,17 @@ public:
int AddBreakpoint(Breakpoint* breakpoint); int AddBreakpoint(Breakpoint* breakpoint);
int RemoveBreakpoint(Breakpoint* breakpoint); int RemoveBreakpoint(Breakpoint* breakpoint);
void FindBreakpoints(
uint64_t address, std::vector<Breakpoint*>& out_breakpoints);
void OnFunctionDefined(FunctionInfo* symbol_info, Function* function);
private: private:
Runtime* runtime_; Runtime* runtime_;
Mutex* breakpoints_lock_;
typedef std::multimap<uint64_t, Breakpoint*> BreakpointsMultimap;
BreakpointsMultimap breakpoints_;
}; };

View File

@ -63,6 +63,7 @@ Entry::Status EntryTable::GetOrCreate(uint64_t address, Entry** out_entry) {
// Create and return for initialization. // Create and return for initialization.
entry = new Entry(); entry = new Entry();
entry->address = address; entry->address = address;
entry->end_address = 0;
entry->status = Entry::STATUS_COMPILING; entry->status = Entry::STATUS_COMPILING;
entry->function = 0; entry->function = 0;
map_[address] = entry; map_[address] = entry;
@ -72,3 +73,19 @@ Entry::Status EntryTable::GetOrCreate(uint64_t address, Entry** out_entry) {
*out_entry = entry; *out_entry = entry;
return status; return status;
} }
std::vector<Function*> EntryTable::FindWithAddress(uint64_t address) {
std::vector<Function*> fns;
LockMutex(lock_);
for (auto it = map_.begin(); it != map_.end(); ++it) {
Entry* entry = it->second;
if (address >= entry->address &&
address <= entry->end_address) {
if (entry->status == Entry::STATUS_READY) {
fns.push_back(entry->function);
}
}
}
UnlockMutex(lock_);
return fns;
}

View File

@ -28,6 +28,7 @@ typedef struct Entry_t {
} Status; } Status;
uint64_t address; uint64_t address;
uint64_t end_address;
Status status; Status status;
Function* function; Function* function;
} Entry; } Entry;
@ -41,6 +42,8 @@ public:
Entry* Get(uint64_t address); Entry* Get(uint64_t address);
Entry::Status GetOrCreate(uint64_t address, Entry** out_entry); Entry::Status GetOrCreate(uint64_t address, Entry** out_entry);
std::vector<Function*> FindWithAddress(uint64_t address);
private: private:
// TODO(benvanik): replace with a better data structure. // TODO(benvanik): replace with a better data structure.
Mutex* lock_; Mutex* lock_;

View File

@ -18,9 +18,43 @@ using namespace alloy::runtime;
Function::Function(Type type, uint64_t address) : Function::Function(Type type, uint64_t address) :
type_(type), address_(address), debug_info_(0) { type_(type), address_(address), debug_info_(0) {
// TODO(benvanik): create on demand?
lock_ = AllocMutex();
} }
Function::~Function() { Function::~Function() {
FreeMutex(lock_);
}
int Function::AddBreakpoint(Breakpoint* breakpoint) {
LockMutex(lock_);
bool found = false;
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
if (*it == breakpoint) {
found = true;
}
}
if (!found) {
breakpoints_.push_back(breakpoint);
AddBreakpointImpl(breakpoint);
}
UnlockMutex(lock_);
return found ? 1 : 0;
}
int Function::RemoveBreakpoint(Breakpoint* breakpoint) {
LockMutex(lock_);
bool found = false;
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
if (*it == breakpoint) {
breakpoints_.erase(it);
RemoveBreakpointImpl(breakpoint);
found = true;
break;
}
}
UnlockMutex(lock_);
return found ? 0 : 1;
} }
int Function::Call(ThreadState* thread_state, uint64_t return_address) { int Function::Call(ThreadState* thread_state, uint64_t return_address) {

View File

@ -17,6 +17,7 @@
namespace alloy { namespace alloy {
namespace runtime { namespace runtime {
class Breakpoint;
class FunctionInfo; class FunctionInfo;
class ThreadState; class ThreadState;
@ -38,15 +39,24 @@ public:
DebugInfo* debug_info() const { return debug_info_; } DebugInfo* debug_info() const { return debug_info_; }
void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; } void set_debug_info(DebugInfo* debug_info) { debug_info_ = debug_info; }
int AddBreakpoint(Breakpoint* breakpoint);
int RemoveBreakpoint(Breakpoint* breakpoint);
int Call(ThreadState* thread_state, uint64_t return_address); int Call(ThreadState* thread_state, uint64_t return_address);
protected: protected:
virtual int AddBreakpointImpl(Breakpoint* breakpoint) { return 0; }
virtual int RemoveBreakpointImpl(Breakpoint* breakpoint) { return 0; }
virtual int CallImpl(ThreadState* thread_state, uint64_t return_address) = 0; virtual int CallImpl(ThreadState* thread_state, uint64_t return_address) = 0;
protected: protected:
Type type_; Type type_;
uint64_t address_; uint64_t address_;
DebugInfo* debug_info_; DebugInfo* debug_info_;
// TODO(benvanik): move elsewhere? DebugData?
Mutex* lock_;
std::vector<Breakpoint*> breakpoints_;
}; };

View File

@ -143,6 +143,10 @@ Runtime::ModuleList Runtime::GetModules() {
return clone; return clone;
} }
std::vector<Function*> Runtime::FindFunctionsWithAddress(uint64_t address) {
return entry_table_.FindWithAddress(address);
}
int Runtime::ResolveFunction(uint64_t address, Function** out_function) { int Runtime::ResolveFunction(uint64_t address, Function** out_function) {
*out_function = NULL; *out_function = NULL;
Entry* entry; Entry* entry;
@ -162,6 +166,7 @@ int Runtime::ResolveFunction(uint64_t address, Function** out_function) {
entry->status = Entry::STATUS_FAILED; entry->status = Entry::STATUS_FAILED;
return result; return result;
} }
entry->end_address = symbol_info->end_address();
status = entry->status = Entry::STATUS_READY; status = entry->status = Entry::STATUS_READY;
} }
if (status == Entry::STATUS_READY) { if (status == Entry::STATUS_READY) {
@ -240,6 +245,10 @@ int Runtime::DemandFunction(
return result; return result;
} }
symbol_info->set_function(function); symbol_info->set_function(function);
// Before we give the symbol back to the rest, let the debugger know.
debugger_->OnFunctionDefined(symbol_info, function);
symbol_info->set_status(SymbolInfo::STATUS_DEFINED); symbol_info->set_status(SymbolInfo::STATUS_DEFINED);
symbol_status = symbol_info->status(); symbol_status = symbol_info->status();
} }

View File

@ -48,6 +48,8 @@ public:
Module* GetModule(const char* name); Module* GetModule(const char* name);
ModuleList GetModules(); ModuleList GetModules();
std::vector<Function*> FindFunctionsWithAddress(uint64_t address);
int LookupFunctionInfo(uint64_t address, FunctionInfo** out_symbol_info); int LookupFunctionInfo(uint64_t address, FunctionInfo** out_symbol_info);
int LookupFunctionInfo(Module* module, uint64_t address, int LookupFunctionInfo(Module* module, uint64_t address,
FunctionInfo** out_symbol_info); FunctionInfo** out_symbol_info);