Moving source map to Function.
This commit is contained in:
parent
5aa50b3c18
commit
b0425f7ee2
|
@ -68,7 +68,7 @@ void* Arena::Alloc(size_t size) {
|
||||||
|
|
||||||
void Arena::Rewind(size_t size) { active_chunk_->offset -= size; }
|
void Arena::Rewind(size_t size) { active_chunk_->offset -= size; }
|
||||||
|
|
||||||
void* Arena::CloneContents() {
|
size_t Arena::CalculateSize() {
|
||||||
size_t total_length = 0;
|
size_t total_length = 0;
|
||||||
Chunk* chunk = head_chunk_;
|
Chunk* chunk = head_chunk_;
|
||||||
while (chunk) {
|
while (chunk) {
|
||||||
|
@ -78,9 +78,14 @@ void* Arena::CloneContents() {
|
||||||
}
|
}
|
||||||
chunk = chunk->next;
|
chunk = chunk->next;
|
||||||
}
|
}
|
||||||
|
return total_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Arena::CloneContents() {
|
||||||
|
size_t total_length = CalculateSize();
|
||||||
void* result = malloc(total_length);
|
void* result = malloc(total_length);
|
||||||
uint8_t* p = (uint8_t*)result;
|
uint8_t* p = (uint8_t*)result;
|
||||||
chunk = head_chunk_;
|
Chunk* chunk = head_chunk_;
|
||||||
while (chunk) {
|
while (chunk) {
|
||||||
std::memcpy(p, chunk->buffer, chunk->offset);
|
std::memcpy(p, chunk->buffer, chunk->offset);
|
||||||
p += chunk->offset;
|
p += chunk->offset;
|
||||||
|
@ -92,6 +97,19 @@ void* Arena::CloneContents() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arena::CloneContents(void* buffer, size_t buffer_length) {
|
||||||
|
uint8_t* p = (uint8_t*)buffer;
|
||||||
|
Chunk* chunk = head_chunk_;
|
||||||
|
while (chunk) {
|
||||||
|
std::memcpy(p, chunk->buffer, chunk->offset);
|
||||||
|
p += chunk->offset;
|
||||||
|
if (chunk == active_chunk_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chunk = chunk->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Arena::Chunk::Chunk(size_t chunk_size)
|
Arena::Chunk::Chunk(size_t chunk_size)
|
||||||
: next(nullptr), capacity(chunk_size), buffer(0), offset(0) {
|
: next(nullptr), capacity(chunk_size), buffer(0), offset(0) {
|
||||||
buffer = reinterpret_cast<uint8_t*>(malloc(capacity));
|
buffer = reinterpret_cast<uint8_t*>(malloc(capacity));
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
|
@ -31,6 +32,11 @@ class Arena {
|
||||||
void Rewind(size_t size);
|
void Rewind(size_t size);
|
||||||
|
|
||||||
void* CloneContents();
|
void* CloneContents();
|
||||||
|
template <typename T>
|
||||||
|
void CloneContents(std::vector<T>& buffer) {
|
||||||
|
buffer.resize(CalculateSize() / sizeof(T));
|
||||||
|
CloneContents(buffer.data(), buffer.size() * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Chunk {
|
class Chunk {
|
||||||
|
@ -45,7 +51,9 @@ class Arena {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
size_t CalculateSize();
|
||||||
|
void CloneContents(void* buffer, size_t buffer_length);
|
||||||
|
|
||||||
size_t chunk_size_;
|
size_t chunk_size_;
|
||||||
Chunk* head_chunk_;
|
Chunk* head_chunk_;
|
||||||
Chunk* active_chunk_;
|
Chunk* active_chunk_;
|
||||||
|
|
|
@ -75,17 +75,21 @@ bool X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||||
// Reset when we leave.
|
// Reset when we leave.
|
||||||
xe::make_reset_scope(this);
|
xe::make_reset_scope(this);
|
||||||
|
|
||||||
|
// Create now, and populate as we go.
|
||||||
|
// We may throw it away if we fail.
|
||||||
|
auto fn = std::make_unique<X64Function>(symbol_info);
|
||||||
|
|
||||||
// Lower HIR -> x64.
|
// Lower HIR -> x64.
|
||||||
void* machine_code = nullptr;
|
void* machine_code = nullptr;
|
||||||
size_t code_size = 0;
|
size_t code_size = 0;
|
||||||
if (!emitter_->Emit(symbol_info, builder, debug_info_flags, debug_info.get(),
|
if (!emitter_->Emit(symbol_info, builder, debug_info_flags, debug_info.get(),
|
||||||
machine_code, code_size)) {
|
machine_code, code_size, fn->source_map())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash generated machine code.
|
// Stash generated machine code.
|
||||||
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmMachineCode) {
|
if (debug_info_flags & DebugInfoFlags::kDebugInfoDisasmMachineCode) {
|
||||||
DumpMachineCode(debug_info.get(), machine_code, code_size, &string_buffer_);
|
DumpMachineCode(machine_code, code_size, fn->source_map(), &string_buffer_);
|
||||||
debug_info->set_machine_code_disasm(string_buffer_.ToString());
|
debug_info->set_machine_code_disasm(string_buffer_.ToString());
|
||||||
string_buffer_.Reset();
|
string_buffer_.Reset();
|
||||||
}
|
}
|
||||||
|
@ -98,21 +102,19 @@ bool X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
X64Function* fn = new X64Function(symbol_info);
|
|
||||||
fn->set_debug_info(std::move(debug_info));
|
fn->set_debug_info(std::move(debug_info));
|
||||||
fn->Setup(reinterpret_cast<uint8_t*>(machine_code), code_size);
|
fn->Setup(reinterpret_cast<uint8_t*>(machine_code), code_size);
|
||||||
|
|
||||||
*out_function = fn;
|
// Pass back ownership.
|
||||||
|
*out_function = fn.release();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
void X64Assembler::DumpMachineCode(
|
||||||
size_t code_size, StringBuffer* str) {
|
void* machine_code, size_t code_size,
|
||||||
auto source_map_entries = debug_info->source_map_entries();
|
const std::vector<SourceMapEntry>& source_map, StringBuffer* str) {
|
||||||
auto source_map_count = debug_info->source_map_count();
|
|
||||||
auto source_map_index = 0;
|
auto source_map_index = 0;
|
||||||
uint32_t next_code_offset = source_map_entries[0].code_offset;
|
uint32_t next_code_offset = source_map[0].code_offset;
|
||||||
|
|
||||||
const uint8_t* code_ptr = reinterpret_cast<uint8_t*>(machine_code);
|
const uint8_t* code_ptr = reinterpret_cast<uint8_t*>(machine_code);
|
||||||
size_t remaining_code_size = code_size;
|
size_t remaining_code_size = code_size;
|
||||||
|
@ -125,11 +127,11 @@ void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
||||||
auto code_offset =
|
auto code_offset =
|
||||||
uint32_t(code_ptr - reinterpret_cast<uint8_t*>(machine_code));
|
uint32_t(code_ptr - reinterpret_cast<uint8_t*>(machine_code));
|
||||||
if (code_offset >= next_code_offset &&
|
if (code_offset >= next_code_offset &&
|
||||||
source_map_index < source_map_count) {
|
source_map_index < source_map.size()) {
|
||||||
auto& source_map_entry = source_map_entries[source_map_index];
|
auto& source_map_entry = source_map[source_map_index];
|
||||||
str->AppendFormat("%.8X ", source_map_entry.source_offset);
|
str->AppendFormat("%.8X ", source_map_entry.source_offset);
|
||||||
++source_map_index;
|
++source_map_index;
|
||||||
next_code_offset = source_map_entries[source_map_index].code_offset;
|
next_code_offset = source_map[source_map_index].code_offset;
|
||||||
} else {
|
} else {
|
||||||
str->Append(" ");
|
str->Append(" ");
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
#define XENIA_BACKEND_X64_X64_ASSEMBLER_H_
|
#define XENIA_BACKEND_X64_X64_ASSEMBLER_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "xenia/base/string_buffer.h"
|
#include "xenia/base/string_buffer.h"
|
||||||
#include "xenia/cpu/backend/assembler.h"
|
#include "xenia/cpu/backend/assembler.h"
|
||||||
|
#include "xenia/cpu/function.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
@ -39,8 +41,9 @@ class X64Assembler : public Assembler {
|
||||||
Function** out_function) override;
|
Function** out_function) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
void DumpMachineCode(void* machine_code, size_t code_size,
|
||||||
size_t code_size, StringBuffer* str);
|
const std::vector<SourceMapEntry>& source_map,
|
||||||
|
StringBuffer* str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
X64Backend* x64_backend_;
|
X64Backend* x64_backend_;
|
||||||
|
|
|
@ -67,13 +67,7 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator)
|
||||||
processor_(backend->processor()),
|
processor_(backend->processor()),
|
||||||
backend_(backend),
|
backend_(backend),
|
||||||
code_cache_(backend->code_cache()),
|
code_cache_(backend->code_cache()),
|
||||||
allocator_(allocator),
|
allocator_(allocator) {
|
||||||
feature_flags_(0),
|
|
||||||
current_instr_(0),
|
|
||||||
debug_info_(nullptr),
|
|
||||||
debug_info_flags_(0),
|
|
||||||
source_map_count_(0),
|
|
||||||
stack_size_(0) {
|
|
||||||
if (FLAGS_enable_haswell_instructions) {
|
if (FLAGS_enable_haswell_instructions) {
|
||||||
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tAVX2) ? kX64EmitAVX2 : 0;
|
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tAVX2) ? kX64EmitAVX2 : 0;
|
||||||
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tFMA) ? kX64EmitFMA : 0;
|
feature_flags_ |= cpu_.has(Xbyak::util::Cpu::tFMA) ? kX64EmitFMA : 0;
|
||||||
|
@ -95,16 +89,14 @@ X64Emitter::~X64Emitter() = default;
|
||||||
|
|
||||||
bool X64Emitter::Emit(FunctionInfo* function_info, HIRBuilder* builder,
|
bool X64Emitter::Emit(FunctionInfo* function_info, HIRBuilder* builder,
|
||||||
uint32_t debug_info_flags, DebugInfo* debug_info,
|
uint32_t debug_info_flags, DebugInfo* debug_info,
|
||||||
void*& out_code_address, size_t& out_code_size) {
|
void*& out_code_address, size_t& out_code_size,
|
||||||
|
std::vector<SourceMapEntry>& out_source_map) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Reset.
|
// Reset.
|
||||||
debug_info_ = debug_info;
|
debug_info_ = debug_info;
|
||||||
debug_info_flags_ = debug_info_flags;
|
debug_info_flags_ = debug_info_flags;
|
||||||
if (debug_info_flags_ & DebugInfoFlags::kDebugInfoSourceMap) {
|
|
||||||
source_map_count_ = 0;
|
|
||||||
source_map_arena_.Reset();
|
source_map_arena_.Reset();
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the generator with code.
|
// Fill the generator with code.
|
||||||
size_t stack_size = 0;
|
size_t stack_size = 0;
|
||||||
|
@ -117,10 +109,7 @@ bool X64Emitter::Emit(FunctionInfo* function_info, HIRBuilder* builder,
|
||||||
out_code_address = Emplace(stack_size, function_info);
|
out_code_address = Emplace(stack_size, function_info);
|
||||||
|
|
||||||
// Stash source map.
|
// Stash source map.
|
||||||
if (debug_info_flags_ & DebugInfoFlags::kDebugInfoSourceMap) {
|
source_map_arena_.CloneContents(out_source_map);
|
||||||
debug_info->InitializeSourceMap(
|
|
||||||
source_map_count_, (SourceMapEntry*)source_map_arena_.CloneContents());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +255,6 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
|
||||||
entry->source_offset = static_cast<uint32_t>(i->src1.offset);
|
entry->source_offset = static_cast<uint32_t>(i->src1.offset);
|
||||||
entry->hir_offset = uint32_t(i->block->ordinal << 16) | i->ordinal;
|
entry->hir_offset = uint32_t(i->block->ordinal << 16) | i->ordinal;
|
||||||
entry->code_offset = static_cast<uint32_t>(getSize() + 1);
|
entry->code_offset = static_cast<uint32_t>(getSize() + 1);
|
||||||
source_map_count_++;
|
|
||||||
|
|
||||||
if (FLAGS_debug) {
|
if (FLAGS_debug) {
|
||||||
nop();
|
nop();
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
#ifndef XENIA_BACKEND_X64_X64_EMITTER_H_
|
#ifndef XENIA_BACKEND_X64_X64_EMITTER_H_
|
||||||
#define XENIA_BACKEND_X64_X64_EMITTER_H_
|
#define XENIA_BACKEND_X64_X64_EMITTER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "xenia/base/arena.h"
|
#include "xenia/base/arena.h"
|
||||||
|
#include "xenia/cpu/function.h"
|
||||||
#include "xenia/cpu/hir/hir_builder.h"
|
#include "xenia/cpu/hir/hir_builder.h"
|
||||||
#include "xenia/cpu/hir/instr.h"
|
#include "xenia/cpu/hir/instr.h"
|
||||||
#include "xenia/cpu/hir/value.h"
|
#include "xenia/cpu/hir/value.h"
|
||||||
|
@ -117,7 +120,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
|
|
||||||
bool Emit(FunctionInfo* function_info, hir::HIRBuilder* builder,
|
bool Emit(FunctionInfo* function_info, hir::HIRBuilder* builder,
|
||||||
uint32_t debug_info_flags, DebugInfo* debug_info,
|
uint32_t debug_info_flags, DebugInfo* debug_info,
|
||||||
void*& out_code_address, size_t& out_code_size);
|
void*& out_code_address, size_t& out_code_size,
|
||||||
|
std::vector<SourceMapEntry>& out_source_map);
|
||||||
|
|
||||||
static uint32_t PlaceData(Memory* memory);
|
static uint32_t PlaceData(Memory* memory);
|
||||||
|
|
||||||
|
@ -201,23 +205,22 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
void EmitTraceUserCallReturn();
|
void EmitTraceUserCallReturn();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Processor* processor_;
|
Processor* processor_ = nullptr;
|
||||||
X64Backend* backend_;
|
X64Backend* backend_ = nullptr;
|
||||||
X64CodeCache* code_cache_;
|
X64CodeCache* code_cache_ = nullptr;
|
||||||
XbyakAllocator* allocator_;
|
XbyakAllocator* allocator_ = nullptr;
|
||||||
Xbyak::util::Cpu cpu_;
|
Xbyak::util::Cpu cpu_;
|
||||||
uint32_t feature_flags_;
|
uint32_t feature_flags_ = 0;
|
||||||
|
|
||||||
Xbyak::Label* epilog_label_ = nullptr;
|
Xbyak::Label* epilog_label_ = nullptr;
|
||||||
|
|
||||||
hir::Instr* current_instr_;
|
hir::Instr* current_instr_ = nullptr;
|
||||||
|
|
||||||
DebugInfo* debug_info_;
|
DebugInfo* debug_info_ = nullptr;
|
||||||
uint32_t debug_info_flags_;
|
uint32_t debug_info_flags_ = 0;
|
||||||
size_t source_map_count_;
|
|
||||||
Arena source_map_arena_;
|
Arena source_map_arena_;
|
||||||
|
|
||||||
size_t stack_size_;
|
size_t stack_size_ = 0;
|
||||||
|
|
||||||
static const uint32_t gpr_reg_map_[GPR_COUNT];
|
static const uint32_t gpr_reg_map_[GPR_COUNT];
|
||||||
static const uint32_t xmm_reg_map_[XMM_COUNT];
|
static const uint32_t xmm_reg_map_[XMM_COUNT];
|
||||||
|
|
|
@ -18,59 +18,15 @@ DebugInfo::DebugInfo()
|
||||||
: source_disasm_(nullptr),
|
: source_disasm_(nullptr),
|
||||||
raw_hir_disasm_(nullptr),
|
raw_hir_disasm_(nullptr),
|
||||||
hir_disasm_(nullptr),
|
hir_disasm_(nullptr),
|
||||||
machine_code_disasm_(nullptr),
|
machine_code_disasm_(nullptr) {}
|
||||||
source_map_count_(0),
|
|
||||||
source_map_entries_(nullptr) {}
|
|
||||||
|
|
||||||
DebugInfo::~DebugInfo() {
|
DebugInfo::~DebugInfo() {
|
||||||
free(source_map_entries_);
|
|
||||||
free(source_disasm_);
|
free(source_disasm_);
|
||||||
free(raw_hir_disasm_);
|
free(raw_hir_disasm_);
|
||||||
free(hir_disasm_);
|
free(hir_disasm_);
|
||||||
free(machine_code_disasm_);
|
free(machine_code_disasm_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugInfo::InitializeSourceMap(size_t source_map_count,
|
|
||||||
SourceMapEntry* source_map) {
|
|
||||||
source_map_count_ = source_map_count;
|
|
||||||
source_map_entries_ = source_map;
|
|
||||||
|
|
||||||
// TODO(benvanik): ensure sorted in some way? MC offset?
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceMapEntry* DebugInfo::LookupSourceOffset(uint32_t offset) {
|
|
||||||
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
|
||||||
for (size_t n = 0; n < source_map_count_; n++) {
|
|
||||||
auto entry = &source_map_entries_[n];
|
|
||||||
if (entry->source_offset == offset) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceMapEntry* DebugInfo::LookupHIROffset(uint32_t offset) {
|
|
||||||
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
|
||||||
for (size_t n = 0; n < source_map_count_; n++) {
|
|
||||||
auto entry = &source_map_entries_[n];
|
|
||||||
if (entry->hir_offset >= offset) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceMapEntry* DebugInfo::LookupCodeOffset(uint32_t offset) {
|
|
||||||
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
|
||||||
for (int64_t n = source_map_count_ - 1; n >= 0; n--) {
|
|
||||||
auto entry = &source_map_entries_[n];
|
|
||||||
if (entry->code_offset <= offset) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return source_map_count_ ? &source_map_entries_[0] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugInfo::Dump() {
|
void DebugInfo::Dump() {
|
||||||
if (source_disasm_) {
|
if (source_disasm_) {
|
||||||
printf("PPC:\n%s\n", source_disasm_);
|
printf("PPC:\n%s\n", source_disasm_);
|
||||||
|
|
|
@ -26,7 +26,6 @@ enum DebugInfoFlags : uint32_t {
|
||||||
kDebugInfoDisasmMachineCode = (1 << 4),
|
kDebugInfoDisasmMachineCode = (1 << 4),
|
||||||
kDebugInfoAllDisasm = kDebugInfoDisasmSource | kDebugInfoDisasmRawHir |
|
kDebugInfoAllDisasm = kDebugInfoDisasmSource | kDebugInfoDisasmRawHir |
|
||||||
kDebugInfoDisasmHir | kDebugInfoDisasmMachineCode,
|
kDebugInfoDisasmHir | kDebugInfoDisasmMachineCode,
|
||||||
kDebugInfoSourceMap = (1 << 5),
|
|
||||||
kDebugInfoTraceFunctions = (1 << 6),
|
kDebugInfoTraceFunctions = (1 << 6),
|
||||||
kDebugInfoTraceFunctionCoverage = (1 << 7) | kDebugInfoTraceFunctions,
|
kDebugInfoTraceFunctionCoverage = (1 << 7) | kDebugInfoTraceFunctions,
|
||||||
kDebugInfoTraceFunctionReferences = (1 << 8) | kDebugInfoTraceFunctions,
|
kDebugInfoTraceFunctionReferences = (1 << 8) | kDebugInfoTraceFunctions,
|
||||||
|
@ -38,12 +37,6 @@ enum DebugInfoFlags : uint32_t {
|
||||||
kDebugInfoAll = 0xFFFFFFFF,
|
kDebugInfoAll = 0xFFFFFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SourceMapEntry_s {
|
|
||||||
uint32_t source_offset; // Original source address/offset.
|
|
||||||
uint32_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b)
|
|
||||||
uint32_t code_offset; // Offset from emitted code start.
|
|
||||||
} SourceMapEntry;
|
|
||||||
|
|
||||||
class DebugInfo {
|
class DebugInfo {
|
||||||
public:
|
public:
|
||||||
DebugInfo();
|
DebugInfo();
|
||||||
|
@ -71,13 +64,6 @@ class DebugInfo {
|
||||||
const char* machine_code_disasm() const { return machine_code_disasm_; }
|
const char* machine_code_disasm() const { return machine_code_disasm_; }
|
||||||
void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; }
|
void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; }
|
||||||
|
|
||||||
size_t source_map_count() const { return source_map_count_; }
|
|
||||||
SourceMapEntry* source_map_entries() const { return source_map_entries_; }
|
|
||||||
void InitializeSourceMap(size_t source_map_count, SourceMapEntry* source_map);
|
|
||||||
SourceMapEntry* LookupSourceOffset(uint32_t offset);
|
|
||||||
SourceMapEntry* LookupHIROffset(uint32_t offset);
|
|
||||||
SourceMapEntry* LookupCodeOffset(uint32_t offset);
|
|
||||||
|
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -90,9 +76,6 @@ class DebugInfo {
|
||||||
char* raw_hir_disasm_;
|
char* raw_hir_disasm_;
|
||||||
char* hir_disasm_;
|
char* hir_disasm_;
|
||||||
char* machine_code_disasm_;
|
char* machine_code_disasm_;
|
||||||
|
|
||||||
size_t source_map_count_;
|
|
||||||
SourceMapEntry* source_map_entries_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -23,6 +23,39 @@ Function::Function(FunctionInfo* symbol_info)
|
||||||
|
|
||||||
Function::~Function() = default;
|
Function::~Function() = default;
|
||||||
|
|
||||||
|
const SourceMapEntry* Function::LookupSourceOffset(uint32_t offset) const {
|
||||||
|
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
||||||
|
for (size_t i = 0; i < source_map_.size(); ++i) {
|
||||||
|
const auto& entry = source_map_[i];
|
||||||
|
if (entry.source_offset == offset) {
|
||||||
|
return &entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceMapEntry* Function::LookupHIROffset(uint32_t offset) const {
|
||||||
|
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
||||||
|
for (size_t i = 0; i < source_map_.size(); ++i) {
|
||||||
|
const auto& entry = source_map_[i];
|
||||||
|
if (entry.hir_offset >= offset) {
|
||||||
|
return &entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SourceMapEntry* Function::LookupCodeOffset(uint32_t offset) const {
|
||||||
|
// TODO(benvanik): binary search? We know the list is sorted by code order.
|
||||||
|
for (int64_t i = source_map_.size() - 1; i >= 0; --i) {
|
||||||
|
const auto& entry = source_map_[i];
|
||||||
|
if (entry.code_offset <= offset) {
|
||||||
|
return &entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source_map_.empty() ? nullptr : &source_map_[0];
|
||||||
|
}
|
||||||
|
|
||||||
bool Function::AddBreakpoint(Breakpoint* breakpoint) {
|
bool Function::AddBreakpoint(Breakpoint* breakpoint) {
|
||||||
std::lock_guard<xe::mutex> guard(lock_);
|
std::lock_guard<xe::mutex> guard(lock_);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
|
@ -24,6 +24,12 @@ namespace cpu {
|
||||||
|
|
||||||
class FunctionInfo;
|
class FunctionInfo;
|
||||||
|
|
||||||
|
struct SourceMapEntry {
|
||||||
|
uint32_t source_offset; // Original source address/offset.
|
||||||
|
uint32_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b)
|
||||||
|
uint32_t code_offset; // Offset from emitted code start.
|
||||||
|
};
|
||||||
|
|
||||||
class Function {
|
class Function {
|
||||||
public:
|
public:
|
||||||
Function(FunctionInfo* symbol_info);
|
Function(FunctionInfo* symbol_info);
|
||||||
|
@ -32,13 +38,18 @@ class Function {
|
||||||
uint32_t address() const { return address_; }
|
uint32_t address() const { return address_; }
|
||||||
FunctionInfo* symbol_info() const { return symbol_info_; }
|
FunctionInfo* symbol_info() const { return symbol_info_; }
|
||||||
|
|
||||||
|
virtual uint8_t* machine_code() const = 0;
|
||||||
|
virtual size_t machine_code_length() const = 0;
|
||||||
|
|
||||||
DebugInfo* debug_info() const { return debug_info_.get(); }
|
DebugInfo* debug_info() const { return debug_info_.get(); }
|
||||||
void set_debug_info(std::unique_ptr<DebugInfo> debug_info) {
|
void set_debug_info(std::unique_ptr<DebugInfo> debug_info) {
|
||||||
debug_info_ = std::move(debug_info);
|
debug_info_ = std::move(debug_info);
|
||||||
}
|
}
|
||||||
|
std::vector<SourceMapEntry>& source_map() { return source_map_; }
|
||||||
|
|
||||||
virtual uint8_t* machine_code() const = 0;
|
const SourceMapEntry* LookupSourceOffset(uint32_t offset) const;
|
||||||
virtual size_t machine_code_length() const = 0;
|
const SourceMapEntry* LookupHIROffset(uint32_t offset) const;
|
||||||
|
const SourceMapEntry* LookupCodeOffset(uint32_t offset) const;
|
||||||
|
|
||||||
bool AddBreakpoint(debug::Breakpoint* breakpoint);
|
bool AddBreakpoint(debug::Breakpoint* breakpoint);
|
||||||
bool RemoveBreakpoint(debug::Breakpoint* breakpoint);
|
bool RemoveBreakpoint(debug::Breakpoint* breakpoint);
|
||||||
|
@ -55,6 +66,7 @@ class Function {
|
||||||
uint32_t address_;
|
uint32_t address_;
|
||||||
FunctionInfo* symbol_info_;
|
FunctionInfo* symbol_info_;
|
||||||
std::unique_ptr<DebugInfo> debug_info_;
|
std::unique_ptr<DebugInfo> debug_info_;
|
||||||
|
std::vector<SourceMapEntry> source_map_;
|
||||||
|
|
||||||
// TODO(benvanik): move elsewhere? DebugData?
|
// TODO(benvanik): move elsewhere? DebugData?
|
||||||
xe::mutex lock_;
|
xe::mutex lock_;
|
||||||
|
|
|
@ -62,7 +62,7 @@ Processor::~Processor() {
|
||||||
|
|
||||||
bool Processor::Setup() {
|
bool Processor::Setup() {
|
||||||
// TODO(benvanik): query mode from debugger?
|
// TODO(benvanik): query mode from debugger?
|
||||||
debug_info_flags_ = DebugInfoFlags::kDebugInfoSourceMap;
|
debug_info_flags_ = 0;
|
||||||
|
|
||||||
auto frontend = std::make_unique<xe::cpu::frontend::PPCFrontend>(this);
|
auto frontend = std::make_unique<xe::cpu::frontend::PPCFrontend>(this);
|
||||||
// TODO(benvanik): set options/etc.
|
// TODO(benvanik): set options/etc.
|
||||||
|
|
|
@ -216,8 +216,7 @@ class Win32StackWalker : public StackWalker {
|
||||||
uint32_t(frame.host_pc) -
|
uint32_t(frame.host_pc) -
|
||||||
uint32_t(uint64_t(function_info->function()->machine_code()));
|
uint32_t(uint64_t(function_info->function()->machine_code()));
|
||||||
auto entry =
|
auto entry =
|
||||||
function_info->function()->debug_info()->LookupCodeOffset(
|
function_info->function()->LookupCodeOffset(host_displacement);
|
||||||
host_displacement);
|
|
||||||
frame.guest_pc = entry->source_offset;
|
frame.guest_pc = entry->source_offset;
|
||||||
} else {
|
} else {
|
||||||
frame.guest_symbol.function_info = nullptr;
|
frame.guest_symbol.function_info = nullptr;
|
||||||
|
|
|
@ -868,7 +868,9 @@ class LintCommand(Command):
|
||||||
'--diff',
|
'--diff',
|
||||||
], throw_on_error=False, stdout_path=difftemp)
|
], throw_on_error=False, stdout_path=difftemp)
|
||||||
with open(difftemp) as f:
|
with open(difftemp) as f:
|
||||||
not_modified = 'no modified files' in f.read()
|
contents = f.read()
|
||||||
|
not_modified = 'no modified files' in contents
|
||||||
|
not_modified = not_modified or 'did not modify' in contents
|
||||||
f.close()
|
f.close()
|
||||||
if os.path.exists(difftemp): os.remove(difftemp)
|
if os.path.exists(difftemp): os.remove(difftemp)
|
||||||
if not not_modified:
|
if not not_modified:
|
||||||
|
|
Loading…
Reference in New Issue