Mostly complete tracing. Probably a lot of bugs.

This commit is contained in:
Ben Vanik
2014-08-14 20:28:44 -07:00
parent cebf595958
commit c275562594
54 changed files with 1052 additions and 161 deletions

View File

@@ -19,6 +19,7 @@
#include <alloy/runtime/runtime.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
#include <xdb/protocol.h>
namespace alloy {
namespace backend {
@@ -66,8 +67,8 @@ X64Emitter::~X64Emitter() {}
int X64Emitter::Initialize() { return 0; }
int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
runtime::DebugInfo* debug_info, void*& out_code_address,
size_t& out_code_size) {
runtime::DebugInfo* debug_info, uint32_t trace_flags,
void*& out_code_address, size_t& out_code_size) {
SCOPE_profile_cpu_f("alloy");
// Reset.
@@ -75,6 +76,7 @@ int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
source_map_count_ = 0;
source_map_arena_.Reset();
}
trace_flags_ = trace_flags;
// Fill the generator with code.
size_t stack_size = 0;
@@ -151,6 +153,19 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
mov(rdx, qword[rcx + 8]); // membase
}
uint64_t trace_base = runtime_->memory()->trace_base();
if (trace_base && trace_flags_ & TRACE_USER_CALLS) {
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallEvent)));
lock();
xadd(qword[rax], r8);
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL) |
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
// Body.
auto block = builder->first_block();
while (block) {
@@ -165,6 +180,16 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
const Instr* instr = block->instr_head;
while (instr) {
const Instr* new_tail = instr;
// Special handling of TRACE_SOURCE.
if (instr->opcode == &OPCODE_TRACE_SOURCE_info) {
if (trace_flags_ & TRACE_SOURCE) {
EmitTraceSource(instr);
}
instr = instr->next;
continue;
}
if (!SelectSequence(*this, instr, &new_tail)) {
// No sequence found!
assert_always();
@@ -179,6 +204,7 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
// Function epilog.
L("epilog");
EmitTraceUserCallReturn();
if (emit_prolog) {
mov(rcx, qword[rsp + StackLayout::GUEST_RCX_HOME]);
add(rsp, (uint32_t)stack_size);
@@ -204,6 +230,129 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
source_map_count_++;
}
void X64Emitter::EmitTraceSource(const Instr* instr) {
uint64_t trace_base = runtime_->memory()->trace_base();
if (!trace_base || !(trace_flags_ & TRACE_SOURCE)) {
return;
}
// TODO(benvanik): make this a function call to some append fn.
uint8_t dest_reg_0 = instr->flags & 0xFF;
uint8_t dest_reg_1 = instr->flags >> 8;
xdb::protocol::EventType event_type;
size_t event_size;
if (dest_reg_0 == 100) {
event_type = xdb::protocol::EventType::INSTR;
event_size = sizeof(xdb::protocol::InstrEvent);
} else if (dest_reg_1 == 100) {
if (dest_reg_0 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R16;
event_size = sizeof(xdb::protocol::InstrEventR16);
} else {
event_type = xdb::protocol::EventType::INSTR_R8;
event_size = sizeof(xdb::protocol::InstrEventR8);
}
} else {
if (dest_reg_0 & (1 << 7) && dest_reg_1 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R16_R16;
event_size = sizeof(xdb::protocol::InstrEventR16R16);
} else if (dest_reg_0 & (1 << 7) && !(dest_reg_1 & (1 << 7))) {
event_type = xdb::protocol::EventType::INSTR_R16_R8;
event_size = sizeof(xdb::protocol::InstrEventR16R8);
} else if (!(dest_reg_0 & (1 << 7)) && dest_reg_1 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R8_R16;
event_size = sizeof(xdb::protocol::InstrEventR8R16);
} else if (!(dest_reg_0 & (1 << 7)) && !(dest_reg_1 & (1 << 7))) {
event_type = xdb::protocol::EventType::INSTR_R8_R8;
event_size = sizeof(xdb::protocol::InstrEventR8R8);
}
}
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(event_size));
lock();
xadd(qword[rax], r8);
// r8 is now the pointer where we can write our event.
// Write the header, which is the same for everything (pretty much).
// Some event types ignore the dest reg, and that's fine.
uint64_t qword_0 = static_cast<uint64_t>(event_type) |
(static_cast<uint64_t>(dest_reg_0) << 8) |
(instr->src1.offset << 32);
mov(rax, qword_0);
mov(qword[r8], rax);
// Write thread ID.
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
switch (event_type) {
case xdb::protocol::EventType::INSTR:
break;
case xdb::protocol::EventType::INSTR_R8:
case xdb::protocol::EventType::INSTR_R16:
if (dest_reg_0 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src2.value, 8);
} else {
EmitTraceSourceAppendValue(instr->src2.value, 8);
}
break;
case xdb::protocol::EventType::INSTR_R8_R8:
case xdb::protocol::EventType::INSTR_R8_R16:
case xdb::protocol::EventType::INSTR_R16_R8:
case xdb::protocol::EventType::INSTR_R16_R16:
mov(word[r8 + 8], dest_reg_0 | static_cast<uint16_t>(dest_reg_1 << 8));
size_t offset = 8;
if (dest_reg_0 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src2.value, offset);
offset += 16;
} else {
EmitTraceSourceAppendValue(instr->src2.value, offset);
offset += 8;
}
if (dest_reg_1 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src3.value, offset);
offset += 16;
} else {
EmitTraceSourceAppendValue(instr->src3.value, offset);
offset += 8;
}
break;
}
}
void X64Emitter::EmitTraceSourceAppendValue(const Value* value,
size_t r8_offset) {
//
}
void X64Emitter::EmitGetCurrentThreadId() {
// rcx must point to context. We could fetch from the stack if needed.
mov(ax,
word[rcx + runtime_->frontend()->context_info()->thread_id_offset()]);
}
void X64Emitter::EmitTraceUserCallReturn() {
auto trace_base = runtime_->memory()->trace_base();
if (!trace_base || !(trace_flags_ & TRACE_USER_CALLS)) {
return;
}
mov(rdx, rax);
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallReturnEvent)));
lock();
xadd(qword[rax], r8);
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL_RETURN) |
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
mov(rax, rdx);
ReloadEDX();
}
void X64Emitter::DebugBreak() {
// TODO(benvanik): notify debugger.
db(0xCC);
@@ -258,7 +407,7 @@ uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
#else
uint64_t return_address =
reinterpret_cast<uint64_t>(__builtin_return_address(0));
#endif // XE_WIN32_LIKE
#endif // XE_LIKE_WIN32
#pragma pack(push, 1)
struct Asm {
uint16_t mov_rax;
@@ -301,6 +450,9 @@ void X64Emitter::Call(const hir::Instr* instr,
// Actually jump/call to rax.
if (instr->flags & CALL_TAIL) {
// Since we skip the prolog we need to mark the return here.
EmitTraceUserCallReturn();
// Pass the callers return address over.
mov(rdx, qword[rsp + StackLayout::GUEST_RET_ADDR]);
@@ -338,7 +490,7 @@ uint64_t ResolveFunctionAddress(void* raw_context, uint64_t target_address) {
#else
uint64_t return_address =
reinterpret_cast<uint64_t>(__builtin_return_address(0));
#endif // XE_WIN32_LIKE
#endif // XE_LIKE_WIN32
#pragma pack(push, 1)
struct Asm {
uint16_t cmp_rdx;
@@ -426,6 +578,9 @@ void X64Emitter::CallIndirect(const hir::Instr* instr, const Reg64& reg) {
// Actually jump/call to rax.
L(skip_resolve);
if (instr->flags & CALL_TAIL) {
// Since we skip the prolog we need to mark the return here.
EmitTraceUserCallReturn();
// Pass the callers return address over.
mov(rdx, qword[rsp + StackLayout::GUEST_RET_ADDR]);
@@ -449,6 +604,24 @@ uint64_t UndefinedCallExtern(void* raw_context, uint64_t symbol_info_ptr) {
void X64Emitter::CallExtern(const hir::Instr* instr,
const FunctionInfo* symbol_info) {
assert_true(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
uint64_t trace_base = runtime_->memory()->trace_base();
if (trace_base & trace_flags_ & TRACE_EXTERN_CALLS) {
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallEvent)));
lock();
xadd(qword[rax], r8);
// TODO(benvanik): get module/ordinal.
uint32_t module_id = 0;
uint32_t ordinal = 0;
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL) |
(static_cast<uint64_t>(0) << 8) | (module_id << 16) |
(ordinal));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
if (!symbol_info->extern_handler()) {
CallNative(UndefinedCallExtern, reinterpret_cast<uint64_t>(symbol_info));
} else {
@@ -466,6 +639,21 @@ void X64Emitter::CallExtern(const hir::Instr* instr,
ReloadEDX();
// rax = host return
}
if (trace_base && trace_flags_ & TRACE_EXTERN_CALLS) {
mov(rax, trace_base);
mov(r8d,
static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallReturnEvent)));
lock();
xadd(qword[rax], r8);
uint32_t module_id = 0;
uint32_t ordinal = 0;
mov(rax,
static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL_RETURN) |
(static_cast<uint64_t>(0) << 8) | (0));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
}
void X64Emitter::CallNative(void* fn) {