More plumbing for breakpoints.
This commit is contained in:
parent
5e9a2c6d27
commit
5881a58c49
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue