Breakpoints triggering.

This commit is contained in:
Ben Vanik 2013-12-22 23:04:24 -08:00
parent 5881a58c49
commit 31b8c02cbf
15 changed files with 155 additions and 2 deletions

View File

@ -25,6 +25,7 @@ using namespace alloy::runtime;
IVMAssembler::IVMAssembler(Backend* backend) :
source_map_arena_(128 * 1024),
Assembler(backend) {
}
@ -47,6 +48,7 @@ int IVMAssembler::Initialize() {
void IVMAssembler::Reset() {
intcode_arena_.Reset();
source_map_arena_.Reset();
scratch_arena_.Reset();
Assembler::Reset();
}
@ -62,6 +64,8 @@ int IVMAssembler::Assemble(
ctx.register_count = 0;
ctx.intcode_count = 0;
ctx.intcode_arena = &intcode_arena_;
ctx.source_map_count = 0;
ctx.source_map_arena = &source_map_arena_;
ctx.scratch_arena = &scratch_arena_;
ctx.label_ref_head = NULL;

View File

@ -35,6 +35,7 @@ public:
private:
Arena intcode_arena_;
Arena source_map_arena_;
Arena scratch_arena_;
};

View File

@ -21,27 +21,86 @@ using namespace alloy::runtime;
IVMFunction::IVMFunction(FunctionInfo* symbol_info) :
register_count_(0), intcode_count_(0), intcodes_(0),
source_map_count_(0), source_map_(0),
GuestFunction(symbol_info) {
}
IVMFunction::~IVMFunction() {
xe_free(intcodes_);
xe_free(source_map_);
}
void IVMFunction::Setup(TranslationContext& ctx) {
register_count_ = ctx.register_count;
intcode_count_ = ctx.intcode_count;
intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents();
source_map_count_ = ctx.source_map_count;
source_map_ = (SourceMapEntry*)ctx.source_map_arena->CloneContents();
}
IntCode* IVMFunction::GetIntCodeAtSourceOffset(uint64_t offset) {
for (size_t n = 0; n < source_map_count_; n++) {
auto entry = &source_map_[n];
if (entry->source_offset == offset) {
return &intcodes_[entry->intcode_index];
}
}
return NULL;
}
int IVMFunction::AddBreakpointImpl(Breakpoint* breakpoint) {
auto i = GetIntCodeAtSourceOffset(breakpoint->address());
if (!i) {
return 1;
}
// TEMP breakpoints always overwrite normal ones.
if (!i->debug_flags ||
breakpoint->type() == Breakpoint::TEMP_TYPE) {
uint64_t breakpoint_ptr = (uint64_t)breakpoint;
i->src2_reg = (uint32_t)breakpoint_ptr;
i->src3_reg = (uint32_t)(breakpoint_ptr >> 32);
}
// Increment breakpoint counter.
++i->debug_flags;
return 0;
}
int IVMFunction::RemoveBreakpointImpl(Breakpoint* breakpoint) {
auto i = GetIntCodeAtSourceOffset(breakpoint->address());
if (!i) {
return 1;
}
// Decrement breakpoint counter.
--i->debug_flags;
i->src2_reg = i->src3_reg = 0;
// If there were other breakpoints, see what they were.
if (i->debug_flags) {
auto old_breakpoint = FindBreakpoint(breakpoint->address());
if (old_breakpoint) {
uint64_t breakpoint_ptr = (uint64_t)breakpoint;
i->src2_reg = (uint32_t)breakpoint_ptr;
i->src3_reg = (uint32_t)(breakpoint_ptr >> 32);
}
}
return 0;
}
void IVMFunction::OnBreakpointHit(ThreadState* thread_state, IntCode* i) {
uint64_t breakpoint_ptr = i->src2_reg | (uint64_t(i->src3_reg) << 32);
Breakpoint* breakpoint = (Breakpoint*)breakpoint_ptr;
// Notify debugger.
// The debugger may choose to wait (blocking us).
auto debugger = thread_state->runtime()->debugger();
debugger->OnBreakpointHit(thread_state, breakpoint);
}
int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) {
// Setup register file on stack.
size_t register_file_size = register_count_ * sizeof(Register);
@ -65,7 +124,12 @@ int IVMFunction::CallImpl(ThreadState* thread_state, uint64_t return_address) {
uint32_t ia = 0;
while (true) {
const IntCode* i = &intcodes_[ia];
IntCode* i = &intcodes_[ia];
if (i->debug_flags) {
OnBreakpointHit(thread_state, i);
}
uint32_t new_ia = i->intcode_fn(ics, i);
if (new_ia == IA_NEXT) {
ia++;

View File

@ -35,13 +35,16 @@ protected:
uint64_t return_address);
private:
IntCode* GetIntCodeAtSourceOffset(uint64_t offset);
void OnBreakpointHit(runtime::ThreadState* thread_state, IntCode* i);
private:
size_t register_count_;
Register* constant_regiters_;
size_t intcode_count_;
IntCode* intcodes_;
// ... source_map_;
size_t source_map_count_;
SourceMapEntry* source_map_;
};

View File

@ -53,6 +53,7 @@ uint32_t AllocConstant(TranslationContext& ctx, uint64_t value,
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = IntCode_INT_LOAD_CONSTANT;
ic->flags = 0;
ic->debug_flags = 0;
ic->dest_reg = ctx.register_count++;
ic->constant.u64 = value;
if (out_ic) {
@ -66,6 +67,7 @@ uint32_t AllocConstant(TranslationContext& ctx, Value* value) {
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = IntCode_INT_LOAD_CONSTANT;
ic->flags = 0;
ic->debug_flags = 0;
ic->dest_reg = ctx.register_count++;
ic->constant.v128 = value->constant.v128;
return ic->dest_reg;
@ -155,6 +157,7 @@ int DispatchToC(TranslationContext& ctx, Instr* i, IntCodeFn fn) {
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = fn;
ic->flags = i->flags;
ic->debug_flags = 0;
ic->dest_reg = dest_reg;
ic->src1_reg = src1_reg;
ic->src2_reg = src2_reg;
@ -210,6 +213,7 @@ int DispatchRegisterRead(
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = fn;
ic->flags = i->flags;
ic->debug_flags = 0;
ic->dest_reg = dest_reg;
ic->src1_reg = src1_reg;
ic->src2_reg = (uint32_t)((uint64_t)cbs);
@ -312,6 +316,7 @@ int DispatchRegisterWrite(
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = fn;
ic->flags = i->flags;
ic->debug_flags = 0;
ic->dest_reg = (uint32_t)(((uint64_t)cbs) >> 32);
ic->src1_reg = src1_reg;
ic->src2_reg = src2_reg;
@ -391,6 +396,7 @@ int Translate_COMMENT(TranslationContext& ctx, Instr* i) {
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = IntCode_COMMENT;
ic->flags = i->flags;
ic->debug_flags = 0;
// HACK HACK HACK
char* src = xestrdupa((char*)i->src1.offset);
uint64_t src_p = (uint64_t)src;
@ -406,6 +412,21 @@ int Translate_NOP(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_NOP);
}
uint32_t IntCode_SOURCE_OFFSET(IntCodeState& ics, const IntCode* i) {
return IA_NEXT;
}
int Translate_SOURCE_OFFSET(TranslationContext& ctx, Instr* i) {
int result = DispatchToC(ctx, i, IntCode_SOURCE_OFFSET);
if (result) {
return result;
}
auto entry = ctx.source_map_arena->Alloc<SourceMapEntry>();
entry->intcode_index = ctx.intcode_count - 1;
entry->source_offset = i->src1.offset;
ctx.source_map_count++;
return 0;
}
uint32_t IntCode_DEBUG_BREAK(IntCodeState& ics, const IntCode* i) {
DFLUSH();
__debugbreak();
@ -3061,6 +3082,8 @@ static const TranslateFn dispatch_table[] = {
Translate_NOP,
Translate_SOURCE_OFFSET,
Translate_DEBUG_BREAK,
Translate_DEBUG_BREAK_TRUE,

View File

@ -63,6 +63,7 @@ typedef uint32_t (*IntCodeFn)(
typedef struct IntCode_s {
IntCodeFn intcode_fn;
uint16_t flags;
uint16_t debug_flags;
uint32_t dest_reg;
union {
@ -88,12 +89,20 @@ typedef struct LabelRef_s {
} LabelRef;
typedef struct SourceMapEntry_s {
uint64_t source_offset;
uint64_t intcode_index;
} SourceMapEntry;
typedef struct {
runtime::RegisterAccessCallbacks* access_callbacks;
uint32_t register_count;
size_t intcode_count;
Arena* intcode_arena;
size_t source_map_count;
Arena* source_map_arena;
Arena* scratch_arena;
LabelRef* label_ref_head;
} TranslationContext;

View File

@ -108,6 +108,10 @@ int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) {
}
}
// Mark source offset for debugging.
// We could omit this if we never wanted to debug.
SourceOffset(i.address);
if (!i.type) {
XELOGCPU("Invalid instruction %.8X %.8X", i.address, i.code);
Comment("INVALID!");

View File

@ -119,6 +119,10 @@ void FunctionBuilder::Dump(StringBuffer* str) {
Instr* i = block->instr_head;
while (i) {
if (i->opcode->flags & OPCODE_FLAG_HIDE) {
i = i->next;
continue;
}
if (i->opcode->num == OPCODE_COMMENT) {
str->Append(" ; %s\n", (char*)i->src1.offset);
i = i->next;
@ -370,6 +374,12 @@ void FunctionBuilder::Nop() {
i->src1.value = i->src2.value = i->src3.value = NULL;
}
void FunctionBuilder::SourceOffset(uint64_t offset) {
Instr* i = AppendInstr(OPCODE_SOURCE_OFFSET_info, 0);
i->src1.offset = offset;
i->src2.value = i->src3.value = NULL;
}
void FunctionBuilder::DebugBreak() {
Instr* i = AppendInstr(OPCODE_DEBUG_BREAK_info, 0);
i->src1.value = i->src2.value = i->src3.value = NULL;

View File

@ -57,6 +57,8 @@ public:
void Nop();
void SourceOffset(uint64_t offset);
// trace info/etc
void DebugBreak();
void DebugBreakTrue(Value* cond);

View File

@ -69,6 +69,8 @@ enum Opcode {
OPCODE_NOP,
OPCODE_SOURCE_OFFSET,
OPCODE_DEBUG_BREAK,
OPCODE_DEBUG_BREAK_TRUE,
@ -174,6 +176,7 @@ enum OpcodeFlags {
OPCODE_FLAG_COMMUNATIVE = (1 << 3),
OPCODE_FLAG_VOLATILE = (1 << 4),
OPCODE_FLAG_IGNORE = (1 << 5),
OPCODE_FLAG_HIDE = (1 << 6),
};
enum OpcodeSignatureType {
@ -188,6 +191,7 @@ enum OpcodeSignatureType {
enum OpcodeSignature {
OPCODE_SIG_X = (OPCODE_SIG_TYPE_X),
OPCODE_SIG_X_L = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_L << 3),
OPCODE_SIG_X_O = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3),
OPCODE_SIG_X_O_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),

View File

@ -20,6 +20,12 @@ DEFINE_OPCODE(
OPCODE_SIG_X,
OPCODE_FLAG_IGNORE);
DEFINE_OPCODE(
OPCODE_SOURCE_OFFSET,
"source_offset",
OPCODE_SIG_X_O,
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE);
DEFINE_OPCODE(
OPCODE_DEBUG_BREAK,
"debug_break",

View File

@ -131,3 +131,8 @@ void Debugger::OnFunctionDefined(FunctionInfo* symbol_info,
}
}
}
void Debugger::OnBreakpointHit(
ThreadState* thread_state, Breakpoint* breakpoint) {
//
}

View File

@ -21,6 +21,7 @@ namespace runtime {
class Function;
class FunctionInfo;
class Runtime;
class ThreadState;
class Breakpoint {
@ -55,6 +56,7 @@ public:
uint64_t address, std::vector<Breakpoint*>& out_breakpoints);
void OnFunctionDefined(FunctionInfo* symbol_info, Function* function);
void OnBreakpointHit(ThreadState* thread_state, Breakpoint* breakpoint);
private:
Runtime* runtime_;

View File

@ -9,6 +9,7 @@
#include <alloy/runtime/function.h>
#include <alloy/runtime/debugger.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
@ -57,6 +58,20 @@ int Function::RemoveBreakpoint(Breakpoint* breakpoint) {
return found ? 0 : 1;
}
Breakpoint* Function::FindBreakpoint(uint64_t address) {
LockMutex(lock_);
Breakpoint* result = NULL;
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
Breakpoint* breakpoint = *it;
if (breakpoint->address() == address) {
result = breakpoint;
break;
}
}
UnlockMutex(lock_);
return result;
}
int Function::Call(ThreadState* thread_state, uint64_t return_address) {
ThreadState* original_thread_state = ThreadState::Get();
if (original_thread_state != thread_state) {

View File

@ -45,6 +45,7 @@ public:
int Call(ThreadState* thread_state, uint64_t return_address);
protected:
Breakpoint* FindBreakpoint(uint64_t address);
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;