Breakpoints triggering.
This commit is contained in:
parent
5881a58c49
commit
31b8c02cbf
|
@ -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;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
|
||||
private:
|
||||
Arena intcode_arena_;
|
||||
Arena source_map_arena_;
|
||||
Arena scratch_arena_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
|
||||
void Nop();
|
||||
|
||||
void SourceOffset(uint64_t offset);
|
||||
|
||||
// trace info/etc
|
||||
void DebugBreak();
|
||||
void DebugBreakTrue(Value* cond);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -131,3 +131,8 @@ void Debugger::OnFunctionDefined(FunctionInfo* symbol_info,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::OnBreakpointHit(
|
||||
ThreadState* thread_state, Breakpoint* breakpoint) {
|
||||
//
|
||||
}
|
|
@ -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_;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue